myclaude-code 8.8.9 → 8.8.11

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.
@@ -0,0 +1,250 @@
1
+ import { existsSync, readdirSync, readFileSync } from 'node:fs'
2
+ import { homedir } from 'node:os'
3
+ import { join } from 'node:path'
4
+
5
+ function getClaudeConfigDir() {
6
+ return process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude')
7
+ }
8
+
9
+ function getTeamsDir() {
10
+ return join(getClaudeConfigDir(), 'teams')
11
+ }
12
+
13
+ function buildNoTeamsText() {
14
+ return [
15
+ `No local agent teams were found under ${getTeamsDir()}.`,
16
+ '',
17
+ 'This usually means no team has been created in this config directory yet.',
18
+ 'Teams are created by the native TeamCreate workflow during an agent-teams session.',
19
+ 'If you are using a GPT gateway through the Anthropic-compatible route, run `/provider validate` first to confirm that native tool calling is actually available.',
20
+ '',
21
+ 'Next step:',
22
+ '1. Launch myclaude with `--agent-teams`.',
23
+ '2. Ask myclaude to create a real team, for example: `Create a team named demo-team with two teammates for this repo.`',
24
+ '',
25
+ 'If you expected teams from another config root, check `CLAUDE_CONFIG_DIR`.',
26
+ ].join('\n')
27
+ }
28
+
29
+ function sanitizeName(value) {
30
+ return String(value || '')
31
+ .replace(/[^a-zA-Z0-9]/g, '-')
32
+ .toLowerCase()
33
+ }
34
+
35
+ function readJsonFile(path) {
36
+ try {
37
+ if (!existsSync(path)) return null
38
+ const raw = readFileSync(path, 'utf8').trim()
39
+ if (!raw) return null
40
+ return JSON.parse(raw)
41
+ } catch {
42
+ return null
43
+ }
44
+ }
45
+
46
+ function getTeamConfigPath(teamName) {
47
+ return join(getTeamsDir(), sanitizeName(teamName), 'config.json')
48
+ }
49
+
50
+ function getTeamSummaries() {
51
+ try {
52
+ const teamsDir = getTeamsDir()
53
+ if (!existsSync(teamsDir)) return []
54
+ const entries = readdirSync(teamsDir, { withFileTypes: true })
55
+ const summaries = []
56
+
57
+ for (const entry of entries) {
58
+ if (!entry.isDirectory()) continue
59
+ const config = readJsonFile(join(teamsDir, entry.name, 'config.json'))
60
+ if (!config || !Array.isArray(config.members)) continue
61
+
62
+ const teammates = config.members.filter(
63
+ member => member && member.name !== 'team-lead',
64
+ )
65
+ const runningCount = teammates.filter(
66
+ member => member.isActive !== false,
67
+ ).length
68
+ const idleCount = teammates.length - runningCount
69
+
70
+ summaries.push({
71
+ name: String(config.name || entry.name),
72
+ memberCount: teammates.length,
73
+ runningCount,
74
+ idleCount,
75
+ })
76
+ }
77
+
78
+ return summaries.sort((left, right) => left.name.localeCompare(right.name))
79
+ } catch {
80
+ return []
81
+ }
82
+ }
83
+
84
+ function getCurrentTeamName(context) {
85
+ try {
86
+ return context?.getAppState?.()?.teamContext?.teamName || null
87
+ } catch {
88
+ return null
89
+ }
90
+ }
91
+
92
+ function resolveTeamName(query) {
93
+ const normalizedQuery = String(query || '').trim().toLowerCase()
94
+ if (!normalizedQuery) return null
95
+ const teams = getTeamSummaries()
96
+ const exact = teams.find(team => team.name.toLowerCase() === normalizedQuery)
97
+ if (exact) return exact.name
98
+ return (
99
+ teams.find(team => team.name.toLowerCase().includes(normalizedQuery))?.name ??
100
+ null
101
+ )
102
+ }
103
+
104
+ function getTeamDetails(teamName) {
105
+ const config = readJsonFile(getTeamConfigPath(teamName))
106
+ if (!config || !Array.isArray(config.members)) return null
107
+ const teammates = config.members.filter(
108
+ member => member && member.name !== 'team-lead',
109
+ )
110
+
111
+ return {
112
+ name: String(config.name || teamName),
113
+ configPath: getTeamConfigPath(teamName),
114
+ teammates: teammates.map(member => ({
115
+ name: String(member.name || 'unknown'),
116
+ agentType: member.agentType ? String(member.agentType) : null,
117
+ model: member.model ? String(member.model) : null,
118
+ status: member.isActive === false ? 'idle' : 'running',
119
+ })),
120
+ }
121
+ }
122
+
123
+ function buildHelpText() {
124
+ return [
125
+ 'Usage: /team [list|current|status [name]|show [name]|help]',
126
+ '',
127
+ `Show real local agent-team status from ${getTeamsDir()}.`,
128
+ '',
129
+ 'Examples:',
130
+ ' /team',
131
+ ' /team list',
132
+ ' /team current',
133
+ ' /team status myteam',
134
+ ' /team show myteam',
135
+ '',
136
+ 'To activate live agent-team workflows in a new session, launch myclaude with',
137
+ '`--agent-teams` or set `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` before start.',
138
+ ].join('\n')
139
+ }
140
+
141
+ function formatTeamLine(team) {
142
+ return `${team.name} · ${team.memberCount} teammates · ${team.runningCount} running · ${team.idleCount} idle`
143
+ }
144
+
145
+ function formatTeamStatus(teamName) {
146
+ const details = getTeamDetails(teamName)
147
+ if (!details) {
148
+ return `No team named '${teamName}' was found under ${getTeamsDir()}.`
149
+ }
150
+
151
+ const sections = [
152
+ `Team: ${details.name}`,
153
+ `Config: ${details.configPath}`,
154
+ `Teammates: ${details.teammates.length}`,
155
+ `Running: ${details.teammates.filter(member => member.status === 'running').length}`,
156
+ `Idle: ${details.teammates.filter(member => member.status === 'idle').length}`,
157
+ ]
158
+
159
+ if (details.teammates.length === 0) {
160
+ sections.push('Members:\n- No teammates are currently registered.')
161
+ return sections.join('\n')
162
+ }
163
+
164
+ sections.push(
165
+ [
166
+ 'Members:',
167
+ ...details.teammates.map(member => {
168
+ const extras = [member.status, member.agentType, member.model].filter(
169
+ Boolean,
170
+ )
171
+ return `- ${member.name} · ${extras.join(' · ')}`
172
+ }),
173
+ ].join('\n'),
174
+ )
175
+
176
+ return sections.join('\n')
177
+ }
178
+
179
+ export async function call(args, context) {
180
+ const trimmedArgs = String(args || '').trim()
181
+
182
+ if (
183
+ !trimmedArgs ||
184
+ trimmedArgs === 'help' ||
185
+ trimmedArgs === '--help' ||
186
+ trimmedArgs === '-h'
187
+ ) {
188
+ const currentTeamName = getCurrentTeamName(context)
189
+ if (currentTeamName) {
190
+ return {
191
+ type: 'text',
192
+ value: formatTeamStatus(currentTeamName),
193
+ }
194
+ }
195
+
196
+ const teams = getTeamSummaries()
197
+ if (teams.length > 0) {
198
+ return {
199
+ type: 'text',
200
+ value: ['Available teams:', ...teams.map(team => `- ${formatTeamLine(team)}`), '', buildHelpText()].join('\n'),
201
+ }
202
+ }
203
+
204
+ return {
205
+ type: 'text',
206
+ value: [
207
+ buildNoTeamsText(),
208
+ '',
209
+ buildHelpText(),
210
+ ].join('\n'),
211
+ }
212
+ }
213
+
214
+ if (trimmedArgs === 'list') {
215
+ const teams = getTeamSummaries()
216
+ return {
217
+ type: 'text',
218
+ value:
219
+ teams.length === 0
220
+ ? buildNoTeamsText()
221
+ : ['Available teams:', ...teams.map(team => `- ${formatTeamLine(team)}`)].join('\n'),
222
+ }
223
+ }
224
+
225
+ const statusMatch = trimmedArgs.match(/^(current|status|show)(?:\s+(.+))?$/i)
226
+ if (statusMatch) {
227
+ const explicitTeamName = statusMatch[2]?.trim()
228
+ const teamName =
229
+ explicitTeamName || getCurrentTeamName(context) || getTeamSummaries()[0]?.name
230
+ return {
231
+ type: 'text',
232
+ value: teamName
233
+ ? formatTeamStatus(teamName)
234
+ : buildNoTeamsText(),
235
+ }
236
+ }
237
+
238
+ const resolvedTeamName = resolveTeamName(trimmedArgs)
239
+ if (resolvedTeamName) {
240
+ return {
241
+ type: 'text',
242
+ value: formatTeamStatus(resolvedTeamName),
243
+ }
244
+ }
245
+
246
+ return {
247
+ type: 'text',
248
+ value: `Unknown /team argument '${trimmedArgs}'. Run /team help for usage.`,
249
+ }
250
+ }
package/image.png ADDED
Binary file
package/install.sh CHANGED
@@ -1,11 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- REPO="${MYCLAUDE_REPO:-mycode699/myclaude-code}"
5
- INSTALL_ROOT="${MYCLAUDE_INSTALL_ROOT:-$HOME/.local/share/myclaude}"
6
- BIN_DIR="${MYCLAUDE_BIN_DIR:-$HOME/.local/bin}"
4
+ PACKAGE="${MYCLAUDE_PACKAGE:-myclaude-code}"
7
5
  VERSION_INPUT="${1:-${MYCLAUDE_VERSION:-latest}}"
8
- ALIASES="${MYCLAUDE_ALIASES:-myclaude mycode claude}"
9
6
 
10
7
  need_cmd() {
11
8
  if ! command -v "$1" >/dev/null 2>&1; then
@@ -14,17 +11,6 @@ need_cmd() {
14
11
  fi
15
12
  }
16
13
 
17
- detect_version() {
18
- if [[ "$VERSION_INPUT" != "latest" ]]; then
19
- printf '%s' "${VERSION_INPUT#v}"
20
- return 0
21
- fi
22
-
23
- curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \
24
- | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v\([^"]*\)".*/\1/p' \
25
- | head -n 1
26
- }
27
-
28
14
  check_node() {
29
15
  need_cmd node
30
16
 
@@ -36,58 +22,33 @@ check_node() {
36
22
  fi
37
23
  }
38
24
 
25
+ resolve_version() {
26
+ if [[ "$VERSION_INPUT" != "latest" ]]; then
27
+ printf '%s' "${VERSION_INPUT#v}"
28
+ return 0
29
+ fi
30
+
31
+ npm view "$PACKAGE" version
32
+ }
33
+
39
34
  main() {
40
- need_cmd curl
41
- need_cmd tar
42
- need_cmd sed
35
+ need_cmd npm
43
36
  check_node
44
37
 
45
- case "$(uname -s)" in
46
- Darwin|Linux) ;;
47
- *)
48
- printf 'This installer currently supports macOS and Linux only.\n' >&2
49
- exit 1
50
- ;;
51
- esac
52
-
53
38
  local version
54
- version="$(detect_version)"
39
+ version="$(resolve_version)"
55
40
  if [[ -z "$version" ]]; then
56
- printf 'Unable to determine the myclaude release version from %s.\n' "$REPO" >&2
41
+ printf 'Unable to determine the latest %s version from npm.\n' "$PACKAGE" >&2
57
42
  exit 1
58
43
  fi
59
44
 
60
- local asset="myclaude-v${version}-node.tar.gz"
61
- local download_url="https://github.com/${REPO}/releases/download/v${version}/${asset}"
62
- local tmp_dir
63
- tmp_dir="$(mktemp -d)"
64
- trap 'rm -rf "$tmp_dir"' EXIT
65
-
66
- printf 'Downloading myclaude %s...\n' "$version"
67
- curl -fL "$download_url" -o "$tmp_dir/$asset"
68
-
69
- tar -xzf "$tmp_dir/$asset" -C "$tmp_dir"
45
+ printf 'Installing %s@%s from npm...\n' "$PACKAGE" "$version"
46
+ npm install -g "${PACKAGE}@${version}" --force
70
47
 
71
- mkdir -p "$INSTALL_ROOT/versions" "$BIN_DIR"
72
- rm -rf "$INSTALL_ROOT/versions/$version"
73
- mv "$tmp_dir/myclaude" "$INSTALL_ROOT/versions/$version"
74
-
75
- ln -sfn "$INSTALL_ROOT/versions/$version" "$INSTALL_ROOT/current"
76
-
77
- local alias_name
78
- for alias_name in $ALIASES; do
79
- ln -sfn "$INSTALL_ROOT/current/bin/$alias_name" "$BIN_DIR/$alias_name"
80
- done
81
-
82
- printf 'Installed myclaude %s to %s\n' "$version" "$INSTALL_ROOT/current"
83
- printf 'Available commands: %s\n' "$ALIASES"
84
-
85
- if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
86
- printf 'Add %s to your PATH if needed:\n' "$BIN_DIR"
87
- printf ' export PATH="%s:$PATH"\n' "$BIN_DIR"
88
- fi
48
+ printf 'Installed %s@%s\n' "$PACKAGE" "$version"
49
+ printf 'Available commands: myclaude, mycode, claude\n'
89
50
 
90
- "$BIN_DIR/myclaude" --version || true
51
+ myclaude --version || true
91
52
  }
92
53
 
93
54
  main "$@"
package/package.json CHANGED
@@ -1,7 +1,18 @@
1
1
  {
2
2
  "name": "myclaude-code",
3
- "version": "8.8.9",
4
- "description": "myclaude v8.8.9 - 我的code · 第一版",
3
+ "version": "8.8.11",
4
+ "description": "myclaude: fast-start AI coding CLI with no Claude Code login and quick third-party API setup",
5
+ "keywords": [
6
+ "myclaude",
7
+ "mycode",
8
+ "cli",
9
+ "ai",
10
+ "anthropic-compatible",
11
+ "openrouter",
12
+ "glm",
13
+ "minimax",
14
+ "kimi"
15
+ ],
5
16
  "type": "module",
6
17
  "bin": {
7
18
  "myclaude": "dist/cli.js",
@@ -9,7 +20,8 @@
9
20
  "claude": "dist/cli.js"
10
21
  },
11
22
  "files": [
12
- "dist/cli.js",
23
+ "dist",
24
+ "image.png",
13
25
  "README.md",
14
26
  "install.sh"
15
27
  ],
@@ -19,7 +31,7 @@
19
31
  },
20
32
  "repository": {
21
33
  "type": "git",
22
- "url": "https://github.com/mycode699/myclaude-code.git"
34
+ "url": "git+https://github.com/mycode699/myclaude-code.git"
23
35
  },
24
36
  "publishConfig": {
25
37
  "access": "public"
@@ -29,7 +41,8 @@
29
41
  "build": "npm run prepare-src && node scripts/build.mjs",
30
42
  "check": "npm run prepare-src && tsc --noEmit",
31
43
  "start": "node dist/cli.js",
32
- "package:release": "node scripts/package-release.mjs"
44
+ "package:release": "node scripts/package-release.mjs",
45
+ "verify:provider": "node scripts/verify-provider-route.mjs"
33
46
  },
34
47
  "engines": {
35
48
  "node": ">=18.0.0"