issuekit 0.1.0__py3-none-any.whl

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,185 @@
1
+ """issuekit init 命令 — 在项目中初始化 Issue 驱动的开发环境。"""
2
+
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ import typer
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+ from rich.tree import Tree
10
+
11
+ from issuekit.agents import AGENT_REGISTRY, get_agent_config
12
+ from issuekit.templates import copy_templates
13
+ from issuekit.knowledge import copy_knowledge_commands
14
+
15
+ console = Console()
16
+
17
+ OK = "[green]+[/green]"
18
+
19
+ ISSUEKIT_DIR = ".issuekit"
20
+
21
+ SUPPORTED_AI = ", ".join(AGENT_REGISTRY.keys())
22
+
23
+ USAGE_EXAMPLES = (
24
+ "\n[dim]用法示例:[/dim]\n"
25
+ " issuekit init --ai cursor\n"
26
+ " issuekit init --ai claude\n"
27
+ " issuekit init --ai cursor --force"
28
+ )
29
+
30
+
31
+ def init(
32
+ ai: str = typer.Option(
33
+ ...,
34
+ help=f"指定 AI 助手:{SUPPORTED_AI}",
35
+ ),
36
+ issues_dir: str = typer.Option(
37
+ "issues",
38
+ "--issues-dir",
39
+ help="Issue 文档存放目录(相对项目根目录,默认:issues)",
40
+ ),
41
+ here: bool = typer.Option(
42
+ True,
43
+ "--here/--no-here",
44
+ help="在当前目录初始化(默认:是)",
45
+ ),
46
+ force: bool = typer.Option(
47
+ False,
48
+ "--force",
49
+ help="如果 .issuekit/ 已存在,强制覆盖",
50
+ ),
51
+ ):
52
+ """在项目中初始化 IssueKit。"""
53
+ agent_config = get_agent_config(ai)
54
+ if not agent_config:
55
+ console.print(
56
+ f"[red]错误:[/red] 不支持的 AI 助手 '{ai}'\n"
57
+ f"[dim]支持的选项:[/dim] {SUPPORTED_AI}"
58
+ f"{USAGE_EXAMPLES}"
59
+ )
60
+ raise typer.Exit(1)
61
+
62
+ project_path = Path.cwd()
63
+ issuekit_path = project_path / ISSUEKIT_DIR
64
+
65
+ if issuekit_path.exists() and not force:
66
+ console.print(
67
+ f"[yellow]提示:[/yellow] {ISSUEKIT_DIR}/ 目录已存在,"
68
+ "如需覆盖请添加 --force 参数。"
69
+ f"{USAGE_EXAMPLES}"
70
+ )
71
+ raise typer.Exit(1)
72
+
73
+ console.print()
74
+ console.print(
75
+ Panel(
76
+ f"[cyan]IssueKit 初始化[/cyan]\n\n"
77
+ f"{'项目':<10} [green]{project_path.name}[/green]\n"
78
+ f"{'AI 助手':<9} [green]{agent_config.name}[/green]\n"
79
+ f"{'Issues':<10} [green]{issues_dir}[/green]\n"
80
+ f"{'路径':<10} [dim]{project_path}[/dim]",
81
+ border_style="cyan",
82
+ padding=(1, 2),
83
+ )
84
+ )
85
+
86
+ # 第 1 步:创建 .issuekit/ 目录结构
87
+ console.print(f"\n[cyan]创建 {ISSUEKIT_DIR}/ 目录...[/cyan]")
88
+
89
+ templates_path = issuekit_path / "templates"
90
+ knowledge_path = issuekit_path / "knowledge"
91
+
92
+ if issuekit_path.exists():
93
+ shutil.rmtree(issuekit_path)
94
+
95
+ templates_path.mkdir(parents=True)
96
+ knowledge_path.mkdir(parents=True)
97
+
98
+ template_count = copy_templates(templates_path)
99
+ console.print(f" {OK} 已复制 {template_count} 个模板到 {ISSUEKIT_DIR}/templates/")
100
+
101
+ # 第 2 步:创建项目配置和知识库配置
102
+ console.print(f"\n[cyan]创建项目配置...[/cyan]")
103
+ write_project_config(issuekit_path, issues_dir=issues_dir)
104
+ console.print(f" {OK} 项目配置已创建:{ISSUEKIT_DIR}/config.yaml")
105
+
106
+ console.print(f"\n[cyan]配置知识库引擎...[/cyan]")
107
+ write_knowledge_config(knowledge_path)
108
+ console.print(f" {OK} 知识库配置已创建:{ISSUEKIT_DIR}/knowledge/")
109
+
110
+ # 第 3 步:安装 AI 助手命令
111
+ console.print(f"\n[cyan]安装 {agent_config.name} 命令...[/cyan]")
112
+ commands_dir = project_path / agent_config.commands_dir
113
+ commands_dir.mkdir(parents=True, exist_ok=True)
114
+
115
+ command_count = copy_knowledge_commands(commands_dir, agent_config)
116
+ from issuekit.agent_commands import install_agent_commands
117
+ cmd_count = install_agent_commands(commands_dir, agent_config)
118
+ command_count += cmd_count
119
+ console.print(f" {OK} 已安装 {command_count} 个命令到 {agent_config.commands_dir}/")
120
+
121
+ # 第 4 步:展示结果
122
+ console.print()
123
+ tree = Tree(f"[bold]{project_path.name}[/bold]")
124
+
125
+ issuekit_tree = tree.add(f"[cyan]{ISSUEKIT_DIR}/[/cyan]")
126
+ issuekit_tree.add("config.yaml")
127
+ tpl_tree = issuekit_tree.add("[cyan]templates/[/cyan]")
128
+ tpl_tree.add("requirement.md")
129
+ tpl_tree.add("technical-design.md")
130
+ tpl_tree.add("test-plan.md")
131
+ tpl_tree.add("release-note.md")
132
+ tpl_tree.add("code-review.md")
133
+ kn_tree = issuekit_tree.add("[cyan]knowledge/[/cyan]")
134
+ kn_tree.add("config.yaml")
135
+
136
+ cmd_tree = tree.add(f"[cyan]{agent_config.commands_dir}/[/cyan]")
137
+ for name in [
138
+ "issuekit.require", "issuekit.design", "issuekit.coding",
139
+ "issuekit.test", "issuekit.release", "issuekit.review",
140
+ "issuekit.change", "issuekit.knowledge",
141
+ ]:
142
+ cmd_tree.add(f"{name}{agent_config.command_ext}")
143
+
144
+ console.print(tree)
145
+
146
+ console.print(
147
+ f"\n[green]IssueKit 初始化完成![/green]\n\n"
148
+ f"下一步:\n"
149
+ f" 1. [cyan]/issuekit.knowledge[/cyan] 构建项目知识摘要(推荐)\n"
150
+ f" 2. [cyan]/issuekit.require[/cyan] 创建第一个 Issue\n"
151
+ )
152
+
153
+
154
+ def write_project_config(issuekit_path: Path, *, issues_dir: str = "issues"):
155
+ """写入 IssueKit 项目级配置文件。"""
156
+ config = issuekit_path / "config.yaml"
157
+ config.write_text(
158
+ "# IssueKit 项目配置\n"
159
+ "\n"
160
+ "# Issue 文档存放目录(相对项目根目录)\n"
161
+ f"issues_dir: {issues_dir}\n",
162
+ encoding="utf-8",
163
+ )
164
+
165
+
166
+ def write_knowledge_config(knowledge_path: Path):
167
+ """写入知识库引擎的默认配置文件。"""
168
+ config = knowledge_path / "config.yaml"
169
+ config.write_text(
170
+ "# IssueKit 知识库配置\n"
171
+ "# 项目上下文摘要自动生成到此目录\n"
172
+ "\n"
173
+ "# 摘要输出目录\n"
174
+ "output_dir: .issuekit/knowledge\n"
175
+ "\n"
176
+ "# 生成的摘要章节\n"
177
+ "sections:\n"
178
+ " - project-overview # 目录结构、技术栈、依赖\n"
179
+ " - architecture # 分层架构、设计模式\n"
180
+ " - api-surface # API 端点、请求/响应约定\n"
181
+ " - data-model # 数据库表、ORM 实体、关系\n"
182
+ " - integrations # 外部服务、SDK、消息队列\n"
183
+ " - conventions # 编码规范、命名约定、错误处理\n",
184
+ encoding="utf-8",
185
+ )
@@ -0,0 +1,32 @@
1
+ """知识库引擎 — 项目上下文总结命令的安装。"""
2
+
3
+ from pathlib import Path
4
+ from importlib import resources
5
+ from issuekit.agents.registry import AgentConfig
6
+
7
+
8
+ def copy_knowledge_commands(commands_dir: Path, agent_config: AgentConfig) -> int:
9
+ """复制知识库相关的 Agent 命令文件,返回安装的文件数。"""
10
+ bundled = resources.files("issuekit") / "bundled_commands"
11
+ knowledge_file = bundled / "issuekit.knowledge.md"
12
+
13
+ if not knowledge_file.is_file():
14
+ return 0
15
+
16
+ content = knowledge_file.read_text(encoding="utf-8")
17
+
18
+ if not agent_config.command_frontmatter:
19
+ content = _strip_frontmatter(content)
20
+
21
+ dest = commands_dir / f"issuekit.knowledge{agent_config.command_ext}"
22
+ dest.write_text(content, encoding="utf-8")
23
+ return 1
24
+
25
+
26
+ def _strip_frontmatter(content: str) -> str:
27
+ """移除 Markdown 内容中的 YAML frontmatter。"""
28
+ if content.startswith("---"):
29
+ end = content.find("---", 3)
30
+ if end != -1:
31
+ return content[end + 3:].lstrip("\n")
32
+ return content
issuekit/templates.py ADDED
@@ -0,0 +1,17 @@
1
+ """模板管理 — 将内置模板复制到项目目录。"""
2
+
3
+ from importlib import resources
4
+ from pathlib import Path
5
+
6
+
7
+ def copy_templates(target_dir: Path) -> int:
8
+ """将所有内置模板复制到目标目录,返回复制的文件数。"""
9
+ bundled = resources.files("issuekit") / "bundled_templates"
10
+ count = 0
11
+ for item in bundled.iterdir():
12
+ if item.name.endswith(".md"):
13
+ content = item.read_text(encoding="utf-8")
14
+ dest = target_dir / item.name
15
+ dest.write_text(content, encoding="utf-8")
16
+ count += 1
17
+ return count
@@ -0,0 +1,177 @@
1
+ Metadata-Version: 2.4
2
+ Name: issuekit
3
+ Version: 0.1.0
4
+ Summary: AI 辅助开发的 Issue 全生命周期工具。从需求分析到代码审核,由你的 AI 编程助手驱动。
5
+ Project-URL: Homepage, https://github.com/xsg22/issue-kit
6
+ Project-URL: Repository, https://github.com/xsg22/issue-kit
7
+ Project-URL: Issues, https://github.com/xsg22/issue-kit/issues
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: ai,claude,codex,cursor,development,issue
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Quality Assurance
16
+ Requires-Python: >=3.10
17
+ Requires-Dist: click>=8.1
18
+ Requires-Dist: pyyaml>=6.0
19
+ Requires-Dist: rich>=13.0
20
+ Requires-Dist: typer>=0.9
21
+ Provides-Extra: test
22
+ Requires-Dist: pytest-cov>=4.0; extra == 'test'
23
+ Requires-Dist: pytest>=7.0; extra == 'test'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # IssueKit
27
+
28
+ AI 辅助开发的 Issue 全生命周期工具。从需求分析到代码审核,由你的 AI 编程助手驱动。
29
+
30
+ ## IssueKit 是什么?
31
+
32
+ IssueKit 为 AI 辅助开发提供结构化的工作流。它提供一组命令,引导你的 AI 编程助手(Cursor、Claude Code、Codex 等)完成一个 Issue 的完整生命周期:
33
+
34
+ | 阶段 | 命令 | 说明 |
35
+ |------|------|------|
36
+ | 1. 需求分析 | `/issuekit.require` | 分析需求,生成面向产品经理的需求文档 |
37
+ | 2. 技术方案 | `/issuekit.design` | 架构设计、接口设计、组件设计、开发步骤 |
38
+ | 3. 编码实现 | `/issuekit.coding` | 按技术方案编码,交叉校验代码与文档一致性 |
39
+ | 4. 测试方案 | `/issuekit.test` | 黑盒业务测试 + 白盒单测/接口测试用例 |
40
+ | 5. 发布准备 | `/issuekit.release` | 生成发布文档,创建 Pull Request |
41
+ | 6. 代码审核 | `/issuekit.review` | 多维度交叉验证(需求、方案、质量) |
42
+
43
+ 还有一个 `/issuekit.knowledge` 命令,用于生成项目上下文摘要,让 AI 助手快速理解项目,无需每次从零扫描。
44
+
45
+ ## 安装
46
+
47
+ ```bash
48
+ pip install issuekit
49
+ ```
50
+
51
+ ## 快速上手
52
+
53
+ ### 第 1 步:初始化
54
+
55
+ 在你的项目根目录运行:
56
+
57
+ ```bash
58
+ cd your-project
59
+ issuekit init --ai cursor
60
+ ```
61
+
62
+ 这会创建 `.issuekit/` 目录(模板 + 知识库配置),并将命令文件安装到 `.cursor/commands/`。
63
+
64
+ 默认 Issue 文档存放在项目根目录的 `issues/` 文件夹下。你也可以自定义目录:
65
+
66
+ ```bash
67
+ issuekit init --ai cursor --issues-dir doc/issues
68
+ ```
69
+
70
+ ### 第 2 步:构建项目知识(可选但推荐)
71
+
72
+ 在 Cursor 中运行命令:
73
+
74
+ ```
75
+ /issuekit.knowledge
76
+ ```
77
+
78
+ AI 助手会分析你的项目,生成结构化的知识摘要到 `.issuekit/knowledge/`。后续的需求分析和技术方案设计会自动读取这些摘要。
79
+
80
+ ### 第 3 步:创建第一个 Issue
81
+
82
+ 假设产品经理给了一个需求:"用户个人资料页面增加修改头像功能,支持裁剪和压缩"。
83
+
84
+ 在 Cursor 中运行:
85
+
86
+ ```
87
+ /issuekit.require 用户个人资料页面增加修改头像功能,支持裁剪和压缩
88
+ ```
89
+
90
+ AI 助手会:
91
+ 1. 深入分析代码,理解现有用户模块的实现
92
+ 2. 生成 Issue ID(如 `FEAT-20260228-avatar-upload`)
93
+ 3. 创建 `issues/FEAT-20260228-avatar-upload/requirement.md`
94
+ 4. 从 master 拉出特性分支 `feature/FEAT-20260228-avatar-upload`
95
+
96
+ 需求文档包含:用户故事(Mermaid 流程图)、边界场景、验收标准、AI 需求评审、待确认问题。
97
+
98
+ ### 第 4 步:设计技术方案
99
+
100
+ 需求确认后,运行:
101
+
102
+ ```
103
+ /issuekit.design
104
+ ```
105
+
106
+ 生成 `technical-design.md`,涵盖技术调研、架构设计、核心流程、组件设计、接口设计、开发步骤。
107
+
108
+ ### 第 5 步:编码实现
109
+
110
+ ```
111
+ /issuekit.coding
112
+ ```
113
+
114
+ AI 助手按技术文档的开发步骤逐步实现,完成后自动交叉校验代码与技术文档、需求文档的一致性。
115
+
116
+ ### 第 6 步:后续流程
117
+
118
+ ```
119
+ /issuekit.test # 生成测试方案
120
+ /issuekit.release # 生成发布文档 + 创建 PR
121
+ /issuekit.review # 多维度代码审核
122
+ ```
123
+
124
+ ## `init` 做了什么
125
+
126
+ 1. 创建 `.issuekit/` 目录:
127
+ - `config.yaml` — 项目配置(Issue 文档目录等)
128
+ - `templates/` — 各阶段文档模板(需求、技术方案、测试、发布、审核)
129
+ - `knowledge/` — 项目上下文知识摘要(由 `/issuekit.knowledge` 生成)
130
+
131
+ 2. 安装 AI 助手命令到对应目录:
132
+ - Cursor → `.cursor/commands/`
133
+ - Claude Code → `.claude/commands/`
134
+ - Codex → `.codex/commands/`
135
+ - GitHub Copilot → `.github/agents/`
136
+
137
+ ## 支持的 AI 助手
138
+
139
+ | AI 助手 | 参数 | 状态 |
140
+ |---------|------|------|
141
+ | Cursor | `--ai cursor` | 已支持 |
142
+ | Claude Code | `--ai claude` | 已支持 |
143
+ | Codex | `--ai codex` | 已支持 |
144
+ | GitHub Copilot | `--ai copilot` | 已支持 |
145
+
146
+ ## 目录结构
147
+
148
+ ```
149
+ .issuekit/
150
+ ├── config.yaml # 项目配置(issues_dir 等)
151
+ ├── templates/ # 文档模板
152
+ │ ├── requirement.md # 需求文档模板
153
+ │ ├── technical-design.md # 技术方案模板
154
+ │ ├── test-plan.md # 测试方案模板
155
+ │ ├── release-note.md # 发布文档模板
156
+ │ └── code-review.md # 代码审核模板
157
+ └── knowledge/ # 项目上下文知识摘要
158
+ ├── config.yaml # 知识库配置
159
+ ├── project-overview.md # 项目概览(/issuekit.knowledge 生成)
160
+ ├── architecture.md # 架构分析
161
+ ├── api-surface.md # API 接口摘要
162
+ ├── data-model.md # 数据模型摘要
163
+ ├── integrations.md # 外部集成摘要
164
+ └── conventions.md # 编码约定摘要
165
+
166
+ issues/ # Issue 文档(默认目录,可通过 --issues-dir 自定义)
167
+ └── FEAT-20260228-xxx/
168
+ ├── requirement.md # 需求文档
169
+ ├── technical-design.md # 技术方案
170
+ ├── test-plan.md # 测试方案
171
+ ├── release-note.md # 发布文档
172
+ └── code-review.md # 代码审核
173
+ ```
174
+
175
+ ## 许可证
176
+
177
+ MIT
@@ -0,0 +1,27 @@
1
+ issuekit/__init__.py,sha256=ALt_H4k70i_3UbBmw_rj8UNI8kimQWrVK9WyKUiXbuI,93
2
+ issuekit/agent_commands.py,sha256=UpdGX9SBD3hYtpzKA_-LTMQQlgPz_501sq0J_kV7IIs,2344
3
+ issuekit/cli.py,sha256=k3i2rvJZe5SCAXUKtAa5HP3Op9p7zyR5L-3cr89yi9Q,2517
4
+ issuekit/templates.py,sha256=c7dSlKVz1rRWRtkAgbxaeeZIMw-IMVvaoCIfUXjAG54,611
5
+ issuekit/agents/__init__.py,sha256=H2ST9gtPIlqqm3ldrFjVyrrtUn7upftpK48JPc3h_kk,181
6
+ issuekit/agents/registry.py,sha256=CvaH14_0vU0iDebtgnVh89yHEojkn8TxcFbbtdzFX30,1779
7
+ issuekit/bundled_commands/issuekit.change.md,sha256=C7N8BH7z3aEzMqcRyn-zGxI8l43wKxDNbfFF0hXKTN4,1861
8
+ issuekit/bundled_commands/issuekit.coding.md,sha256=-dCDJJWpGZGPTaWeCxw0_BgKEiC4fRGDNwf1E4XGgSU,4809
9
+ issuekit/bundled_commands/issuekit.design.md,sha256=u3kVoumgoZJCBJJfIckk_fARaQq4vyzTa_KrwEkRdpk,4464
10
+ issuekit/bundled_commands/issuekit.knowledge.md,sha256=k5oQHTWBjez_EzVRLREhuCvcPVT8lWPG2bPGbjmT2zc,4617
11
+ issuekit/bundled_commands/issuekit.release.md,sha256=vi9tE2S5F7YkiJoy4B8QvadLT1gAoIB12ij68oAYlSM,2397
12
+ issuekit/bundled_commands/issuekit.require.md,sha256=ylT2UQdw9y_zbNNycvYXPyaclxgJi8Sm3IeUETHoVgk,5334
13
+ issuekit/bundled_commands/issuekit.review.md,sha256=Y1VqlbvZrv_sTYN_h3OdZ9XW_wBzGnFnERQ0wH4HRqI,2667
14
+ issuekit/bundled_commands/issuekit.test.md,sha256=MjyaOhL8XzhXoTs0Abg3jeyM0du8Tt0Nl5ecEKF0i3U,3177
15
+ issuekit/bundled_templates/code-review.md,sha256=Ip_x_HX5HXWoerfD8dhK5ANkoVIHYq3Z860j4AydP6M,3425
16
+ issuekit/bundled_templates/release-note.md,sha256=Vq8jNqomoKmsDXSVzr3P7RSeJLerr7_UFtZ0xu1AWeE,2232
17
+ issuekit/bundled_templates/requirement.md,sha256=wn4IM8dpWoY0BEBXfhaFagtI49UMQgBWZv7ZrnpzjNU,3231
18
+ issuekit/bundled_templates/technical-design.md,sha256=GjUQ55q1XYrsDQtyVKx3n6t5Fv8_B4STDnK1f8qy7g4,5792
19
+ issuekit/bundled_templates/test-plan.md,sha256=r9ZUYXm4PbWno4yJWnpAV0pNNpwRmryeW_prOisfcUs,9412
20
+ issuekit/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ issuekit/commands/init.py,sha256=nHrb1xZ8m8pFuGILkzMOlyEkY0ET8tw6-FzPLicnlXY,6507
22
+ issuekit/knowledge/__init__.py,sha256=RDnYb-XeWCVMyrYw8vu1qcWit4Hv3ilC5tjmzP-KHYM,1100
23
+ issuekit-0.1.0.dist-info/METADATA,sha256=gn0VSfj9FiKHQQDaUwfEBLTWVkyCIppGaN0DwLLY3I4,6211
24
+ issuekit-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
25
+ issuekit-0.1.0.dist-info/entry_points.txt,sha256=1ftj_n9rjULfEjjgO0wfBZvSC1_JhY3yS6PLZLFMEtI,46
26
+ issuekit-0.1.0.dist-info/licenses/LICENSE,sha256=XKKSDU9WlUEAyPNlRhq6e2xhVNpJc097JwPZJ1rUnRE,1077
27
+ issuekit-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ issuekit = issuekit.cli:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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.