Commit d6a1e6b
* feat: add `skill` CLI command and `.opencode/tools/` auto-discovery (#341)
Add a top-level `altimate-code skill` command with `list`, `create`, and
`test` subcommands, plus auto-discovery of user CLI tools on PATH.
- `skill list` — shows skills with paired CLI tools, source, description
- `skill create <name>` — scaffolds SKILL.md + CLI tool stub (bash/python/node)
- `skill test <name>` — validates frontmatter, checks tool on PATH, runs `--help`
- Auto-prepend `.opencode/tools/` (project) and `~/.config/altimate-code/tools/`
(global) to PATH in `BashTool` and PTY sessions
- Worktree-aware: `skill create` uses git root, PATH includes worktree tools
- Input validation: regex + length limits, 5s timeout on tool `--help`
- 14 unit tests (42 assertions) covering tool detection, templates, adversarial inputs
- Updated docs: skills.md, tools/custom.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address code review findings for skill CLI (#341)
- Extract `detectToolReferences`, `SHELL_BUILTINS`, `skillSource`,
`isToolOnPath` into `skill-helpers.ts` so tests import production code
instead of duplicating it
- Anchor PATH tool dirs to `Instance.directory` (not `cwd`) to prevent
external_directory workdirs from shadowing project tools
- Change `skill test` to FAIL (not warn) on broken paired tools:
timeouts, non-zero exits, and spawn failures now set `hasErrors`
- Add `.opencode/skills/` to the Discovery Paths doc section for
consistency with `skill create` and the Skill Paths section
- Use `tmpdir()` fixture from `test/fixture/fixture.ts` in tests
instead of manual `fs.mkdtemp` + `afterAll` cleanup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: enrich TUI skill dialog with source and paired tools (#341)
Enhance the `/skills` dialog in the TUI to show:
- Source category (Project / Global / Built-in) instead of flat "Skills"
- Paired CLI tools in the footer (e.g., "Tools: altimate-dbt")
- Reuses `detectToolReferences` and `skillSource` from `skill-helpers.ts`
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: improve skill list UX and TUI dialog (#341)
CLI `skill list`:
- Sort skills alphabetically
- Remove SOURCE column (noisy, not useful)
- Truncate descriptions on word boundaries instead of mid-word
TUI `/skills` dialog:
- Group skills by domain (dbt, SQL, Schema, FinOps, etc.) instead of source
- Truncate descriptions to 80 chars for readability
- Show paired tools compactly in footer (max 2)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add edit and test actions to TUI skills dialog (#341)
The `/skills` dialog now supports keybind actions on the selected skill:
- `ctrl+e` — open the SKILL.md in `$EDITOR` (skips built-in skills)
- `ctrl+t` — run `skill test` and show PASS/FAIL result as a toast
This makes the TUI a complete skill management surface (browse, use,
edit, test) without dropping to the CLI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add `skill install` and `skill show` commands (#341)
New subcommands for the skill CLI:
`skill install <source>`:
- Install skills from GitHub repos: `altimate-code skill install anthropics/skills`
- Install from URL: `altimate-code skill install https://github.com/owner/repo.git`
- Install from local path: `altimate-code skill install ./my-skills`
- `--global` / `-g` flag for user-wide installation
- Duplicate protection (skips already-installed skills)
- Copies full skill directories (SKILL.md + references/ + scripts/)
- Cleans up temp clones after install
`skill show <name>`:
- Display full skill content (name, description, location, tools, content)
- Quick inspection without opening an editor
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: align TUI skill operations with CLI commands (#341)
Add all CLI skill operations to the TUI for feature parity:
`/skills` dialog keybinds:
- `ctrl+o` — view skill content (maps to `skill show`)
- `ctrl+e` — edit SKILL.md in $EDITOR
- `ctrl+t` — test skill and show PASS/FAIL toast (maps to `skill test`)
Slash commands (command palette):
- `/skill-create <name>` — scaffolds a new skill (maps to `skill create`)
- `/skill-install <source>` — install from GitHub/URL (maps to `skill install`)
CLI ↔ TUI mapping:
skill list → /skills dialog
skill show → ctrl+o in dialog
skill create → /skill-create
skill test → ctrl+t in dialog
skill install → /skill-install
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: final validation fixes from release testing (#341)
- Fix name regex: allow single-char first segment (e.g., `a-tool`, `x-ray`)
by changing `[a-z][a-z0-9]+` to `[a-z][a-z0-9]*` with separate length check
- Validate empty/whitespace source in `skill install` (was treating `""` as cwd)
- Add test cases for valid hyphenated names and adversarial install inputs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: replace fake slash commands with real TUI dialogs for create/install (#341)
Remove non-functional `/skill-create` and `/skill-install` slash commands
that only pre-filled input text. Replace with real keybind actions in the
`/skills` dialog:
- `ctrl+n` (create) — opens `DialogPrompt` for skill name, then runs
`altimate-code skill create` and shows result as toast
- `ctrl+i` (install) — opens `DialogPrompt` for source (owner/repo, URL,
or path), then runs `altimate-code skill install` and shows result
Full CLI ↔ TUI parity:
skill list → /skills dialog
skill show → ctrl+o in dialog
skill create → ctrl+n in dialog (input prompt)
skill test → ctrl+t in dialog
skill install → ctrl+i in dialog (input prompt)
skill edit → ctrl+e in dialog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use `process.argv[0]` instead of `"altimate-code"` in TUI subprocess spawns (#341)
TUI keybind actions (create, test, install) were spawning
`"altimate-code"` which resolves to the system-installed binary, not the
currently running one. This causes failures when running a local build
or a different version than what's installed globally.
Fix: use `process.argv[0]` which is the path to the current running
binary in all three spawn sites.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: improve TUI error reporting for skill create/install/test (#341)
- Add explicit `env: { ...process.env }` to all Bun.spawn calls to ensure
NODE_PATH and other env vars are forwarded to subprocess
- Improve error messages: show both stderr and stdout on failure, truncate
to 200 chars, include error class name for catch blocks
- Consistent error format across create, install, and test actions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: inline skill operations in TUI instead of spawning subprocess (#341)
The TUI dialog was spawning `process.argv[0] skill install ...` which
failed because `process.argv[0]` in the compiled Bun binary doesn't
resolve correctly for self-invocation (error: Script not found "skill").
Fix: inline all skill operations directly in the TUI component:
- `createSkillDirect()` — creates SKILL.md + tool via `fs` operations
- `installSkillDirect()` — clones repo via `git clone`, copies SKILL.md
files via `fs`, no subprocess self-invocation needed
- `testSkillDirect()` — spawns the tool's `--help` directly (not via
the altimate-code binary)
This eliminates the subprocess spawning problem entirely. The TUI now
uses the same `Instance`, `Global`, and `fs` APIs as the CLI commands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use async `Bun.spawn` for git clone in TUI install (#341)
`Bun.spawnSync` blocks the TUI event loop during `git clone`, causing
the install toast to show briefly then disappear with nothing installed.
Fix: switch to async `Bun.spawn` with `await proc.exited` so the TUI
stays responsive while cloning. Read stderr via `new Response().text()`
for error messages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: invalidate skill cache after TUI create/install so new skills appear (#341)
The TUI skill dialog showed stale data after installing or creating
skills because `Skill.state` is a singleton cache (via `Instance.state`)
that never re-scans.
Fix:
- Add `State.invalidate(key, init)` to clear a single cached state entry
without disposing all state for the directory
- Add `Skill.invalidate()` that clears the skill cache, so the next call
to `Skill.all()` re-scans all skill directories
- Call `Skill.invalidate()` after successful create/install in the TUI
dialog, so reopening `/skills` shows the newly installed skills
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: invalidate server-side skill cache via API after TUI install/create (#341)
The TUI runs in the main thread but the server (which serves the
skills API) runs in a worker thread. Calling `Skill.invalidate()`
from the TUI component had no effect because it cleared the cache
in the wrong JS context.
Fix:
- Add `?reload=true` query param support to `GET /skill` endpoint
that calls `Skill.invalidate()` in the server/worker context
- TUI calls `GET /skill?reload=true` via `sdk.fetch()` after
successful install/create to invalidate the worker's cache
- Next `/skills` dialog open fetches fresh data from server
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: improve TUI install/create confirmation UX (#341)
Problems:
- "Installing..." toast disappeared immediately (short default duration)
- No verification that skills actually loaded after install
- No guidance on what to do next
Fix:
- Set 30s duration on "Installing..." toast so it persists during clone
- After install/create, call `GET /skill?reload=true` and verify each
installed skill appears in the returned list
- Show detailed confirmation toast (8s duration) with:
- Count and bullet list of installed skill names
- Guidance: "Open /skills to browse, or type /<skill-name> to use"
- Show explicit error if install succeeded but skills didn't load
- Same pattern for create: confirms name and location
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add try/catch and input sanitization to TUI install/create (#341)
Root cause of silent failures: `onConfirm` async callbacks had no
try/catch, so any thrown error was swallowed and no result toast shown.
Fixes:
- Wrap all install/create logic in try/catch with error toast
- Strip trailing dots from input (textarea was appending `.`)
- Strip `.git` suffix from URLs (users paste from browser)
- Trim whitespace and validate before proceeding
- "Installing..." toast now shows 60s duration with helpful text
("This may take a moment while the repo is cloned")
- Empty input shows immediate error instead of proceeding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use 10min timeout for in-progress toast so it never disappears before completion (#341)
The "Installing..." toast used a 60s timeout which could expire on
slow connections. Changed to 600s (10 min) — effectively infinite
since the result toast (`toast.show`) always replaces it on
completion, clearing the old timeout automatically.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: show live progress log in TUI install toast (#341)
Instead of a static "Installing..." message, the toast now updates
in real-time as each step completes:
Installing from dagster-io/skills
Cloning dagster-io/skills...
→ Cloned. Scanning for skills...
→ Found 2 skill(s). Installing...
→ Installed 1/2: dignified-python
→ Installed 2/2: dagster-expert
→ Verifying skills loaded...
Each step calls `toast.show()` which replaces the previous message,
keeping the toast visible throughout. The user always knows what's
happening and how far along the operation is.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove Instance/Global usage from TUI dialog — use sdk.directory (#341)
`Instance` and `Global` only exist in the worker thread context.
The TUI dialog runs in the main thread, so accessing them throws
"No context found for instance".
Fix: pass `sdk.directory` (available from the SDK context in the main
thread) to all skill operations instead of calling `Instance.worktree`
or `Global.Path.cache`. Use `os.homedir()` for cache directory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use git root for TUI skill install target directory (#341)
`sdk.directory` is the cwd where the TUI was launched (e.g.
`packages/opencode/`), not the git worktree root. Skills installed
via TUI went to the wrong `.opencode/skills/` directory.
Fix: add `gitRoot()` helper that runs `git rev-parse --show-toplevel`
to resolve the actual project root, matching what Instance.worktree
does in the worker thread.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add `skill remove` command and ctrl+d in TUI (#341)
New CLI command:
altimate-code skill remove <name>
TUI keybind:
ctrl+d in /skills dialog
Safety:
- Cannot remove skills tracked by git (part of the repo)
- Cannot remove built-in skills (builtin: prefix)
- Removes both skill directory and paired CLI tool
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: parse GitHub web URLs and reduce TUI keybind clutter (#341)
1. GitHub web URLs like
`https://github.com/owner/repo/tree/main/skills/foo`
now correctly extract `owner/repo` and clone the full repo.
Previously tried to clone the `/tree/main` path which isn't a repo.
2. Reduced TUI dialog keybinds from 7 to 4 (edit, create, install,
remove) so the footer isn't cramped. View and test are available
via CLI (`skill show`, `skill test`).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: restore show/test keybinds and wrap footer to fit (#341)
Add `flexWrap="wrap"` to the DialogSelect keybind footer so it
flows to two rows when there are many keybinds, instead of
overflowing off-screen.
Restore all 6 keybinds in /skills dialog:
show ctrl+o | edit ctrl+e | test ctrl+t
create ctrl+n | install ctrl+i | remove ctrl+d
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: replace 6 keybinds with single ctrl+a action picker (#341)
Instead of 6 individual keybinds cramped in the footer, the /skills
dialog now shows a single clean footer:
actions ctrl+a
Pressing ctrl+a on any skill opens a second-level action picker:
┌ Actions: dbt-develop ──────────────────────┐
│ Show details view info, tools, location │
│ Edit in $EDITOR open SKILL.md │
│ Test paired tool run --help on CLI tool │
│ Create new skill scaffold skill + tool │
│ Install from GitHub │
│ Remove skill delete skill + tool │
└────────────────────────────────────────────────┘
- Edit and Remove are hidden for git-tracked/builtin skills
- Enter on the main list still inserts /<skill> (most common action)
- Revert flexWrap on DialogSelect (no longer needed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: return to skill list after action picker completes (#341)
Actions (show, test, remove) were calling `dialog.clear()` which
closed everything. Now they call `reopenSkillList()` which replaces
the action picker with a fresh skill list dialog, so the user stays
in the /skills flow.
- Show: toast shows, skill list reopens behind it
- Test: toast shows result, skill list reopens
- Remove: skill removed, skill list reopens (with updated list)
- Edit: still closes dialog (external editor takes over)
- Create/Install: already used dialog.replace() (unchanged)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: open skill editor in system app instead of inline terminal (#341)
Opening $EDITOR with `stdio: "inherit"` conflicts with the TUI
rendering, corrupts the display, and leaves the user stranded.
Fix: use `open` (macOS) / `xdg-open` (Linux) to open the SKILL.md
in the system default editor as a separate window. The TUI stays
intact, shows a toast with the file path, and returns to the skill
list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: separate per-skill actions from global actions in TUI (#341)
ctrl+a action picker now only shows per-skill actions:
Show details, Edit, Test, Remove
Global actions moved to main skill list footer keybinds:
actions ctrl+a | new ctrl+n | install ctrl+i
This avoids confusion where "Create new skill" and "Install from
GitHub" appeared under "Actions: dbt-develop" even though they
have nothing to do with that skill.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: Esc on action picker goes back to skill list (#341)
Pressing Esc on the action picker was closing the dialog entirely.
Now uses the `onClose` callback of `dialog.replace()` to reopen
the skill list when the action picker is dismissed.
Uses `setTimeout(0)` to defer the reopen so the dialog stack
pop completes first.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: update skills and custom tools docs with all new commands (#341)
skills.md:
- Add `skill show`, `skill install`, `skill remove` to CLI section
- Add TUI keybind reference table (ctrl+a actions, ctrl+n, ctrl+i)
- Document GitHub URL support (web URLs, shorthand, --global)
tools/custom.md:
- Add "Installing Community Skills" section with install/remove examples
- Document TUI install/remove flow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address code review findings from 6-model consensus review (#341)
Security:
- Use `fs.lstat` instead of `fs.stat` during skill install to skip
symlinks (prevents file disclosure from malicious repos)
- Pass `dereference: false` to `fs.cp` for directory copies
Bugs:
- Create cache directory (`~/.cache/altimate-code`) before git clone
so installs work on fresh systems
- TUI `createSkillDirect` now checks if tool already exists before
writing (matches CLI behavior, prevents clobbering user tools)
- Add global tools dir to TUI test PATH (fixes false negatives for
globally installed tools)
UX:
- Allow editing git-tracked skills (only block Remove, not Edit)
- Split `isBuiltinOrTracked` into `isBuiltin` + `isRemovable`
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add telemetry for skill create/install/remove (#341)
New telemetry event types:
- `skill_created` — tracks name, language, source (cli/tui)
- `skill_installed` — tracks install_source, skill_count, skill_names
- `skill_removed` — tracks skill_name, source
All events follow existing patterns:
- Wrapped in try/catch (telemetry never breaks operations)
- Use Telemetry.getContext().sessionId (empty for CLI-only)
- Include timestamp and source discriminator
CLI commands instrumented: create, install, remove.
TUI operations not instrumented (Telemetry runs in worker thread,
TUI in main thread — would need a server endpoint to bridge).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: strip .git suffix from CLI install source to prevent double-append (#341)
`altimate-code skill install owner/repo.git` produced
`https://github.com/owner/repo.git.git`. Now strips `.git` suffix
from the source string before processing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 623d1ac commit d6a1e6b
File tree
13 files changed
+2015
-26
lines changed- docs/docs/configure
- tools
- packages/opencode
- src
- altimate/telemetry
- cli/cmd
- tui/component
- project
- pty
- server
- skill
- tool
- test/cli
13 files changed
+2015
-26
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
| 37 | + | |
| 38 | + | |
38 | 39 | | |
39 | 40 | | |
40 | 41 | | |
| |||
88 | 89 | | |
89 | 90 | | |
90 | 91 | | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
91 | 133 | | |
92 | 134 | | |
93 | | - | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
94 | 182 | | |
95 | 183 | | |
96 | 184 | | |
| |||
104 | 192 | | |
105 | 193 | | |
106 | 194 | | |
| 195 | + | |
| 196 | + | |
107 | 197 | | |
108 | 198 | | |
109 | | - | |
| 199 | + | |
110 | 200 | | |
111 | 201 | | |
112 | 202 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
6 | 88 | | |
7 | 89 | | |
8 | 90 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
350 | 350 | | |
351 | 351 | | |
352 | 352 | | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
353 | 379 | | |
354 | 380 | | |
355 | 381 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
0 commit comments