m365-api 0.1.0 → 0.1.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.
@@ -2,11 +2,11 @@
2
2
 
3
3
  # Publishing and runtime distribution
4
4
 
5
- Every version is packed once with its production dependencies. That exact archive is published to npmjs, the HTTPS distribution site and the GitHub Release. Clients download updates from the distribution site without authenticating to the private source repository or contacting npm's registry.
5
+ Every version is packed once with its production dependencies. Packing uses a temporary directory to set npm's README metadata explicitly to English while retaining the complete Chinese companion; source package metadata is unchanged. That exact archive is published to npmjs, the HTTPS distribution site and the GitHub Release. Clients download updates from the distribution site without authenticating to the private source repository or contacting npm's registry.
6
6
 
7
7
  ## One-time setup
8
8
 
9
- - Register the repository's self-hosted Linux runner and keep its service online.
9
+ - Register the repository's self-hosted Linux runner on the distribution host, add the `m365-api-release` label and keep its service online. Release jobs use that label so their local output is written on the correct host.
10
10
  - Store a granular npm token with package publishing permission and the required automation/2FA permission in repository Secret `NPM_TOKEN`. The initial unscoped package is `m365-api`; the first token must be allowed to create it. Never commit tokens or put them in command arguments. Renew the secret when the token expires.
11
11
  - Configure repository Variable `M365_API_RELEASE_BASE_URL` as `https://m365api.claxlink.top/releases/` and `M365_API_FILES_DIR` as `/srv/m365-api/releases`. The runner must be able to write that directory. npm registry selection is not embedded in client code; only the publish step explicitly targets npmjs.
12
12
  - Point the domain at the distribution host and allow ports 80/443. Caddy serves the directory and automatically obtains and renews its public certificate. Its `caddy` systemd service must be enabled, and its persistent data under `/var/lib/caddy` must survive restarts.
@@ -31,9 +31,11 @@ Every version is packed once with its production dependencies. That exact archiv
31
31
 
32
32
  Replace the example with the version in the package. Do not move an existing published tag or reuse an npm version.
33
33
 
34
- 5. The **Publish npm package and runtime distribution** workflow validates the tag/settings, installs locked dependencies, checks syntax, tests, packs the complete runtime and verifies an offline npm installation using an isolated prefix/data home. It generates an integrity manifest, publishes the archive to npmjs using `NPM_TOKEN`, publishes those same bytes to the distribution directory, advances the public pointers and creates a GitHub Release. A manual workflow run validates and uploads private test artifacts only; it does not publish to npmjs or the public directory.
34
+ 5. The **Publish npm package and runtime distribution** workflow validates the tag/settings, installs locked dependencies, checks syntax, tests, packs the complete runtime and verifies an offline npm installation using an isolated prefix/data home. It generates an integrity manifest, publishes the archive to npmjs using `NPM_TOKEN`, publishes those same bytes to the distribution directory, advances the public pointers and creates a GitHub Release. Tested files are retained privately under `~/m365-api-release-builds/<run>-<attempt>` on the runner, so publishing does not depend on GitHub Actions artifact storage quota. A manual run without `publish_tag` validates only; setting `publish_tag` checks out that existing tag and publishes or recovers it without moving the tag. Package metadata records the checked-out source commit.
35
35
  6. Verify the workflow succeeded, npmjs has the intended version, and the HTTPS manifest identifies the same package/version/integrity. A failed publish must be inspected before retrying. An already published version is accepted only if its integrity matches; backwards `latest` movement is rejected. If published bytes need changing, use a new version.
36
36
 
37
+ To recover an unchanged tagged release using the current workflow, run `gh workflow run release.yml --ref main -f publish_tag=v0.1.0`. Substitute the intended existing tag; leaving that input empty performs a validation-only run. Do not delete and recreate the tag to change its workflow.
38
+
37
39
  ## Public files and updates
38
40
 
39
41
  - `latest.json`: current stable version, archive URL/size/SHA-512 and Node.js requirement.
@@ -63,8 +65,8 @@ Caddy's running service handles certificate renewal automatically; no separate c
63
65
  ## Isolated packaging checks
64
66
 
65
67
  ```sh
66
- npm pack --pack-destination <temporary-directory>
67
- node scripts/smoke-package.mjs <temporary-directory>/m365-api-0.1.0.tgz
68
+ node scripts/pack-release.mjs --pack-destination <temporary-directory>
69
+ node scripts/smoke-package.mjs <temporary-directory>/m365-api-0.1.1.tgz
68
70
  ```
69
71
 
70
72
  The smoke check installs offline with an empty npm cache and an isolated prefix, extracts/self-checks the archive and launches the managed command with `M365_API_PORTABLE=1` and a temporary `M365_API_HOME`. It does not migrate the real host, alter Claude settings or start the user's gateway. Ordinary source installs keep their existing Git update path.
@@ -2,11 +2,11 @@
2
2
 
3
3
  # 发布与运行包分发
4
4
 
5
- 每个版本只打包一次,包含生产依赖。同一个压缩包会发布到 npmjs、HTTPS 分发站和 GitHub Release。客户端更新从分发站下载,不需要私有源码仓库的访问权限,也不访问 npm registry。
5
+ 每个版本只打包一次,包含生产依赖。打包时通过临时目录明确设置 npm 的英文 README 元数据,同时保留完整的中文版,源码中的包元数据保持不变。同一个压缩包会发布到 npmjs、HTTPS 分发站和 GitHub Release。客户端更新从分发站下载,不需要私有源码仓库的访问权限,也不访问 npm registry。
6
6
 
7
7
  ## 一次性配置
8
8
 
9
- - 注册仓库的 Linux 自托管 runner,保持其服务在线。
9
+ - 在分发主机注册仓库的 Linux 自托管 runner,添加 `m365-api-release` 标签并保持服务在线。发布任务通过该标签确保本地文件写入正确主机。
10
10
  - 在仓库 Secret `NPM_TOKEN` 中保存有发包权限及所需自动化/2FA 权限的 npm 细粒度令牌。初始非 scoped 包名为 `m365-api`,首发令牌必须允许创建该包。禁止把令牌提交到仓库或放在命令参数中;令牌过期时更新 Secret。
11
11
  - 仓库 Variable `M365_API_RELEASE_BASE_URL` 设置为 `https://m365api.claxlink.top/releases/`,`M365_API_FILES_DIR` 设置为 `/srv/m365-api/releases`,runner 必须能写入该目录。客户端代码不固定 npm registry,只有发布步骤明确指定 npmjs。
12
12
  - 将域名指向分发主机并放行 80/443。Caddy 提供静态文件服务,自动申请及续期公开证书。启用其 `caddy` systemd 服务,保留 `/var/lib/caddy` 下的持久数据。
@@ -31,9 +31,11 @@
31
31
 
32
32
  示例版本应替换为包内版本。不要移动已经发布的标签,也不要复用 npm 版本。
33
33
 
34
- 5. **Publish npm package and runtime distribution** 工作流会校验标签及配置、安装锁定依赖、检查语法、运行测试、打包完整运行时,并在隔离 prefix/数据目录中验证离线 npm 安装。随后生成校验清单,使用 `NPM_TOKEN` 发布 npmjs,再将同一压缩包发布到分发目录、更新公开指针并创建 GitHub Release。手动运行工作流只做验证并上传私有测试产物,不向 npmjs 或公开目录发布。
34
+ 5. **Publish npm package and runtime distribution** 工作流会校验标签及配置、安装锁定依赖、检查语法、运行测试、打包完整运行时,并在隔离 prefix/数据目录中验证离线 npm 安装。随后生成校验清单,使用 `NPM_TOKEN` 发布 npmjs,再将同一压缩包发布到分发目录、更新公开指针并创建 GitHub Release。已测试文件私有保存在 runner 的 `~/m365-api-release-builds/<运行>-<重试>` 下,不依赖 GitHub Actions 产物存储额度。手动运行且不填写 `publish_tag` 时只验证;填写时会检出对应已有标签并执行发布或恢复,不移动标签。包元数据记录实际检出的源码提交。
35
35
  6. 确认工作流成功、npmjs 版本正确、HTTPS 清单的包名/版本/校验值与之相同。发布失败后先检查原因再重试;已存在版本仅在校验值一致时接受,禁止将 `latest` 回退到旧版本。如需修改已发布字节,必须发布新版本。
36
36
 
37
+ 使用最新工作流恢复源码不变的已打标签版本,可执行 `gh workflow run release.yml --ref main -f publish_tag=v0.1.0`。请替换为目标已有标签;不填该输入时只验证。不要通过删除重建标签来更改发布工作流。
38
+
37
39
  ## 公开文件与更新
38
40
 
39
41
  - `latest.json`:当前稳定版、压缩包 URL/大小/SHA-512 和 Node.js 要求。
@@ -63,8 +65,8 @@ Caddy 服务运行期间会自动续期证书,不需要另建 cron 任务。
63
65
  ## 隔离的打包检查
64
66
 
65
67
  ```sh
66
- npm pack --pack-destination <临时目录>
67
- node scripts/smoke-package.mjs <临时目录>/m365-api-0.1.0.tgz
68
+ node scripts/pack-release.mjs --pack-destination <临时目录>
69
+ node scripts/smoke-package.mjs <临时目录>/m365-api-0.1.1.tgz
68
70
  ```
69
71
 
70
72
  冒烟检查会使用空 npm 缓存和隔离的 prefix 离线安装、解压并自检压缩包,再通过 `M365_API_PORTABLE=1` 和临时 `M365_API_HOME` 启动包命令,不迁移真实主机、不改 Claude 设置,也不启动用户的网关。普通源码安装继续使用原有 Git 更新流程。
package/package-mode.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "releaseBaseUrl": "https://m365api.claxlink.top/releases/",
5
- "sourceCommit": "f1f4f688668740d3214575ff8a88870766770b54"
5
+ "sourceCommit": "12dc0a5734e8731ef0d56d8a27d17059e9f81adc"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "m365-api",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "Local API adapter for Microsoft 365 Copilot Code models and reasoning effort",
6
6
  "engines": {
@@ -16,7 +16,7 @@
16
16
  "claude:configure": "node scripts/cli.mjs claude:configure",
17
17
  "claude:desktop:configure": "node scripts/cli.mjs claude:desktop:configure",
18
18
  "claude:mcp:allow": "node scripts/cli.mjs claude:mcp:allow",
19
- "check": "node --check src/server.mjs && node --check src/client.mjs && node --check src/auth.mjs && node --check src/anthropic.mjs && node --check src/response-parameters.mjs && node --check src/partial-text.mjs && node --check src/text-smoother.mjs && node --check src/device-login.mjs && node --check src/browser-login.mjs && node --check src/claude-config.mjs && node --check src/claude-discovery.mjs && node --check src/conversation-store.mjs && node --check src/transcript-state.mjs && node --check src/reply-cache.mjs && node --check src/compaction.mjs && node --check src/upstream-context.mjs && node --check src/images.mjs && node --check src/files.mjs && node --check src/completions.mjs && node --check public/app.js && node --check scripts/install-claude.mjs && node --check scripts/configure-claude.mjs && node --check scripts/configure-claude-desktop.mjs && node --check scripts/login.mjs && node --check scripts/start.mjs && node --check scripts/ensure-dependencies.mjs && node --check scripts/spawn-background.mjs && node --check src/gateway-config.mjs && node --check scripts/service.mjs && node --check scripts/cli.mjs && node --check src/installation.mjs && node --check src/release.mjs && node --check scripts/package-install.mjs && node --check scripts/package-launcher.mjs && node --check scripts/postinstall.mjs && node --check scripts/prepare-package.mjs && node --check scripts/runtime-check.mjs && node --check scripts/runtime-update.mjs && node --check scripts/release-artifact.mjs && node --check scripts/smoke-package.mjs && node --check scripts/github-release.mjs",
19
+ "check": "node --check src/server.mjs && node --check src/client.mjs && node --check src/auth.mjs && node --check src/anthropic.mjs && node --check src/response-parameters.mjs && node --check src/partial-text.mjs && node --check src/text-smoother.mjs && node --check src/device-login.mjs && node --check src/browser-login.mjs && node --check src/claude-config.mjs && node --check src/claude-discovery.mjs && node --check src/conversation-store.mjs && node --check src/transcript-state.mjs && node --check src/reply-cache.mjs && node --check src/compaction.mjs && node --check src/upstream-context.mjs && node --check src/images.mjs && node --check src/files.mjs && node --check src/completions.mjs && node --check public/app.js && node --check scripts/install-claude.mjs && node --check scripts/configure-claude.mjs && node --check scripts/configure-claude-desktop.mjs && node --check scripts/login.mjs && node --check scripts/start.mjs && node --check scripts/ensure-dependencies.mjs && node --check scripts/spawn-background.mjs && node --check src/gateway-config.mjs && node --check scripts/service.mjs && node --check scripts/cli.mjs && node --check src/installation.mjs && node --check src/release.mjs && node --check scripts/package-install.mjs && node --check scripts/package-launcher.mjs && node --check scripts/postinstall.mjs && node --check scripts/prepare-package.mjs && node --check scripts/runtime-check.mjs && node --check scripts/runtime-update.mjs && node --check scripts/release-artifact.mjs && node --check scripts/smoke-package.mjs && node --check scripts/github-release.mjs && node --check scripts/pack-release.mjs",
20
20
  "setup": "node scripts/cli.mjs setup",
21
21
  "stop": "node scripts/cli.mjs stop",
22
22
  "restart": "node scripts/cli.mjs restart",
@@ -69,5 +69,7 @@
69
69
  "bundleDependencies": true,
70
70
  "publishConfig": {
71
71
  "access": "public"
72
- }
72
+ },
73
+ "readme": "[![简体中文](.github/assets/lang-zh-CN.svg)](https://github.com/shaowei_microsoft/m365-api/blob/main/README.zh-CN.md)\n\n# m365-api\n\nConnect Microsoft 365 Copilot Code to Claude CLI, Claude Desktop, and OpenAI-compatible clients.\n\n## Quick start (Windows PowerShell)\n\nInstall **Node.js 24+, Edge**, and your preferred Claude client. Your work account must have access to the [Microsoft 365 Copilot Code page](https://copilot.cloud.microsoft/code?origindomain=microsoft365&es=SSR&redirfrom=mcmToCcm#/sessions).\n\n```powershell\nnpm install -g m365-api\nm365-api setup\n```\n\nSetup asks for a port, initially **8787**, saves it, configures the discovered Claude clients, and starts the gateway. It prints the absolute gateway and client configuration paths. Choose a port directly with:\n\n```powershell\nm365-api setup --port 8787\n```\n\nIf your network cannot reach npmjs, install the same package with its bundled dependencies from the distribution site:\n\n```powershell\nnpm install -g https://m365api.claxlink.top/releases/latest.tgz --no-audit --no-fund\n```\n\nThe first startup attempts silent Microsoft sign-in. If interaction or MFA is required:\n\n```powershell\nm365-api login --headed\nm365-api start\n```\n\n## Existing Git installations\n\nGlobal npm installation detects the old source deployment from its registered user PATH or startup entry. It preserves the account, saved port, conversation mappings and attachments, removes only the old m365-api PATH registration, and replaces existing m365-api startup entries with a stable launcher. The source directory remains intact. A previously running gateway is restarted after validation; active client connections block migration. Unrelated PATH entries, startup items, Claude settings and MCP configuration are preserved.\n\n**Reopen your terminal** after migration. If there are multiple source installations, select the intended one with `m365-api migrate --legacy-root <path>`. npm installs using `--ignore-scripts` defer installation until the command first runs. Local dependency installations do not migrate your machine.\n\n## Usage\n\n```powershell\nclaude --model opus --effort max\nclaude --model sonnet --effort max\n```\n\nIn Claude Desktop, restart and use the selected `m365-api` profile, displayed as **M365APP**. Open **Code** and select a local project.\n\n| Interface | Default address |\n|---|---|\n| Web interface / Claude base URL | http://127.0.0.1:8787 |\n| OpenAI base URL | http://127.0.0.1:8787/v1 |\n\nUse the address shown by setup or status if you selected another port. Upload files through the web interface or compatible Claude / Anthropic file APIs; see [reference](docs/reference.md).\n\n## Common commands\n\n| Action | Command |\n|---|---|\n| Configure clients and start | `m365-api setup` |\n| Start / stop / restart | `m365-api start` / `m365-api stop` / `m365-api restart` |\n| Show status and configuration paths | `m365-api status` |\n| Check for an update | `m365-api update --check-only` |\n| Download, verify and apply an update | `m365-api update` |\n| Run in the foreground | `m365-api start --foreground` |\n| Preview client configuration | `m365-api setup --check-only` |\n| Enable / disable startup | `m365-api startup` / `m365-api startup:remove` |\n| Sign in interactively | `m365-api login --headed` |\n\nStopping interrupts active requests and does not disable startup. New npm installations do not enable startup automatically; existing startup settings are preserved during migration. Development-only command registration and test commands are available from Git checkouts.\n\n## Updates and data\n\nnpm installations keep data under **%LOCALAPPDATA%\\m365-api** on Windows. The saved settings are in `.env`; credentials, conversations and attachments are under `.local`. `M365_API_HOME` selects another data directory. Setup and status show the actual absolute configuration path.\n\n`m365-api update` downloads a complete runtime from **m365api.claxlink.top**, verifies its SHA-512 digest, stages it alongside the current version and performs a self-check before switching. It requires no Git or npm-registry access. A running gateway is restarted and health-checked; failure attempts to restore the previous version and service. User data is shared across runtime versions. Existing client connections block a restart. Preview does not change files or stop the gateway.\n\nTo use another distribution source, run `m365-api update --source <HTTPS URL>`. Package installation inherits your npm registry settings; the runtime distribution address is configured separately. Node.js and Edge remain system prerequisites.\n\nFor source development, configuration, file APIs and limitations, see the [reference](docs/reference.md) and [contribution guide](CONTRIBUTING.md).\n",
74
+ "readmeFilename": "README.md"
73
75
  }
@@ -0,0 +1,46 @@
1
+ import { cp, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { within } from '../src/installation.mjs';
8
+
9
+ const exec = promisify(execFile);
10
+
11
+ export async function stageRelease(root, staging) {
12
+ const pkg = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
13
+ for (const entry of [...pkg.files, 'node_modules']) {
14
+ const source = resolve(root, entry), destination = resolve(staging, entry);
15
+ if (!within(root, source) || !within(staging, destination)) throw new Error('Invalid package file path.');
16
+ await mkdir(dirname(destination), { recursive: true });
17
+ await cp(source, destination, { recursive: true });
18
+ }
19
+ // npm otherwise chooses a translated README according to filesystem/glob order.
20
+ // Supply its supported metadata explicitly, only in the temporary package.
21
+ pkg.readme = await readFile(join(root, 'README.md'), 'utf8');
22
+ pkg.readmeFilename = 'README.md';
23
+ await writeFile(join(staging, 'package.json'), JSON.stringify(pkg, null, 2) + '\n');
24
+ }
25
+
26
+ async function main(args) {
27
+ if (args.length !== 2 || args[0] !== '--pack-destination') throw new Error('Usage: node scripts/pack-release.mjs --pack-destination <directory>');
28
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
29
+ const destination = resolve(args[1]);
30
+ await mkdir(destination, { recursive: true });
31
+ await exec(process.execPath, [join(root, 'scripts/prepare-package.mjs')], { cwd: root, windowsHide: true });
32
+ const temporary = await mkdtemp(join(tmpdir(), 'm365-release-pack-'));
33
+ try {
34
+ await stageRelease(root, temporary);
35
+ const npm = process.env.npm_execpath || (process.platform === 'win32'
36
+ ? join(dirname(process.execPath), 'node_modules/npm/bin/npm-cli.js')
37
+ : resolve(dirname(process.execPath), '../lib/node_modules/npm/bin/npm-cli.js'));
38
+ const { stdout } = await exec(process.execPath, [npm, 'pack', '--ignore-scripts', '--pack-destination', destination, '--json'],
39
+ { cwd: temporary, windowsHide: true, timeout: 180000, maxBuffer: 8 * 1024 * 1024 });
40
+ process.stdout.write(stdout);
41
+ } finally {
42
+ if (within(tmpdir(), temporary)) await rm(temporary, { recursive: true, force: true });
43
+ }
44
+ }
45
+
46
+ if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main(process.argv.slice(2));
@@ -27,6 +27,8 @@ try {
27
27
  await exec(process.execPath, [join(root, 'scripts/postinstall.mjs')], { env: { ...env, M365_API_SKIP_POSTINSTALL: '0', npm_config_global: 'true' }, windowsHide: true, timeout: 180000 });
28
28
  const { stdout } = await exec(process.execPath, [join(root, 'scripts/cli.mjs'), '--version'], { env, windowsHide: true, timeout: 45000 });
29
29
  const pkg = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'));
30
+ assert.equal(pkg.readmeFilename, 'README.md');
31
+ assert.equal(pkg.readme, await readFile(join(root, 'README.md'), 'utf8'));
30
32
  assert.ok(stdout.includes(`m365-api ${pkg.version}`));
31
33
  const command = process.platform === 'win32'
32
34
  ? await exec('cmd.exe', ['/d', '/c', 'm365-api', '--version'], { cwd: temp, env: { ...env, PATH: prefix + ';' + process.env.PATH }, windowsHide: true, timeout: 45000 })
@@ -1,166 +0,0 @@
1
- # Changes
2
-
3
-
4
- ## 2.0.2
5
-
6
- * Rename bin to `node-which`
7
-
8
- ## 2.0.1
9
-
10
- * generate changelog and publish on version bump
11
- * enforce 100% test coverage
12
- * Promise interface
13
-
14
- ## 2.0.0
15
-
16
- * Parallel tests, modern JavaScript, and drop support for node < 8
17
-
18
- ## 1.3.1
19
-
20
- * update deps
21
- * update travis
22
-
23
- ## v1.3.0
24
-
25
- * Add nothrow option to which.sync
26
- * update tap
27
-
28
- ## v1.2.14
29
-
30
- * appveyor: drop node 5 and 0.x
31
- * travis-ci: add node 6, drop 0.x
32
-
33
- ## v1.2.13
34
-
35
- * test: Pass missing option to pass on windows
36
- * update tap
37
- * update isexe to 2.0.0
38
- * neveragain.tech pledge request
39
-
40
- ## v1.2.12
41
-
42
- * Removed unused require
43
-
44
- ## v1.2.11
45
-
46
- * Prevent changelog script from being included in package
47
-
48
- ## v1.2.10
49
-
50
- * Use env.PATH only, not env.Path
51
-
52
- ## v1.2.9
53
-
54
- * fix for paths starting with ../
55
- * Remove unused `is-absolute` module
56
-
57
- ## v1.2.8
58
-
59
- * bullet items in changelog that contain (but don't start with) #
60
-
61
- ## v1.2.7
62
-
63
- * strip 'update changelog' changelog entries out of changelog
64
-
65
- ## v1.2.6
66
-
67
- * make the changelog bulleted
68
-
69
- ## v1.2.5
70
-
71
- * make a changelog, and keep it up to date
72
- * don't include tests in package
73
- * Properly handle relative-path executables
74
- * appveyor
75
- * Attach error code to Not Found error
76
- * Make tests pass on Windows
77
-
78
- ## v1.2.4
79
-
80
- * Fix typo
81
-
82
- ## v1.2.3
83
-
84
- * update isexe, fix regression in pathExt handling
85
-
86
- ## v1.2.2
87
-
88
- * update deps, use isexe module, test windows
89
-
90
- ## v1.2.1
91
-
92
- * Sometimes windows PATH entries are quoted
93
- * Fixed a bug in the check for group and user mode bits. This bug was introduced during refactoring for supporting strict mode.
94
- * doc cli
95
-
96
- ## v1.2.0
97
-
98
- * Add support for opt.all and -as cli flags
99
- * test the bin
100
- * update travis
101
- * Allow checking for multiple programs in bin/which
102
- * tap 2
103
-
104
- ## v1.1.2
105
-
106
- * travis
107
- * Refactored and fixed undefined error on Windows
108
- * Support strict mode
109
-
110
- ## v1.1.1
111
-
112
- * test +g exes against secondary groups, if available
113
- * Use windows exe semantics on cygwin & msys
114
- * cwd should be first in path on win32, not last
115
- * Handle lower-case 'env.Path' on Windows
116
- * Update docs
117
- * use single-quotes
118
-
119
- ## v1.1.0
120
-
121
- * Add tests, depend on is-absolute
122
-
123
- ## v1.0.9
124
-
125
- * which.js: root is allowed to execute files owned by anyone
126
-
127
- ## v1.0.8
128
-
129
- * don't use graceful-fs
130
-
131
- ## v1.0.7
132
-
133
- * add license to package.json
134
-
135
- ## v1.0.6
136
-
137
- * isc license
138
-
139
- ## 1.0.5
140
-
141
- * Awful typo
142
-
143
- ## 1.0.4
144
-
145
- * Test for path absoluteness properly
146
- * win: Allow '' as a pathext if cmd has a . in it
147
-
148
- ## 1.0.3
149
-
150
- * Remove references to execPath
151
- * Make `which.sync()` work on Windows by honoring the PATHEXT variable.
152
- * Make `isExe()` always return true on Windows.
153
- * MIT
154
-
155
- ## 1.0.2
156
-
157
- * Only files can be exes
158
-
159
- ## 1.0.1
160
-
161
- * Respect the PATHEXT env for win32 support
162
- * should 0755 the bin
163
- * binary
164
- * guts
165
- * package
166
- * 1st