mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-07-11 13:33:41 +03:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3820917e08 |
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "cc-1c-skills",
|
|
||||||
"interface": {
|
|
||||||
"displayName": "1C Skills"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "1c-skills",
|
|
||||||
"source": {
|
|
||||||
"source": "url",
|
|
||||||
"url": "https://github.com/Nikolay-Shirokov/cc-1c-skills.git",
|
|
||||||
"ref": "port-codex"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"installation": "AVAILABLE"
|
|
||||||
},
|
|
||||||
"category": "Development"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "1c-skills-py",
|
|
||||||
"source": {
|
|
||||||
"source": "url",
|
|
||||||
"url": "https://github.com/Nikolay-Shirokov/cc-1c-skills.git",
|
|
||||||
"ref": "port-codex-py"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"installation": "AVAILABLE"
|
|
||||||
},
|
|
||||||
"category": "Development"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/claude-code-marketplace-manifest.json",
|
|
||||||
"name": "cc-1c-skills",
|
|
||||||
"description": "Маркетплейс навыков для разработки на платформе 1С:Предприятие",
|
|
||||||
"owner": {
|
|
||||||
"name": "Nikolay Shirokov"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "1c-skills",
|
|
||||||
"source": "./",
|
|
||||||
"description": "[PowerShell] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "1c-skills-py",
|
|
||||||
"source": {
|
|
||||||
"source": "github",
|
|
||||||
"repo": "Nikolay-Shirokov/cc-1c-skills",
|
|
||||||
"ref": "port-claude-code-py"
|
|
||||||
},
|
|
||||||
"description": "[Python] То же — для Linux/Mac или когда PowerShell недоступен."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
||||||
"name": "1c-skills",
|
|
||||||
"description": "[PowerShell] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент.",
|
|
||||||
"author": {
|
|
||||||
"name": "Nikolay Shirokov"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/Nikolay-Shirokov/cc-1c-skills",
|
|
||||||
"repository": "https://github.com/Nikolay-Shirokov/cc-1c-skills",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"1c",
|
|
||||||
"1c-dev",
|
|
||||||
"cf",
|
|
||||||
"cfe",
|
|
||||||
"epf",
|
|
||||||
"erf",
|
|
||||||
"metadata",
|
|
||||||
"configuration",
|
|
||||||
"extension",
|
|
||||||
"form",
|
|
||||||
"report",
|
|
||||||
"skd",
|
|
||||||
"data-processor",
|
|
||||||
"mxl",
|
|
||||||
"web-client",
|
|
||||||
"testing",
|
|
||||||
"test-automation"
|
|
||||||
],
|
|
||||||
"skills": "./.claude/skills/"
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# Коммиты, которые git blame должен «проскакивать» (механические правки —
|
|
||||||
# не меняют авторство содержимого). Включить локально:
|
|
||||||
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
|
||||||
# GitHub/GitLab уважают этот файл в blame-UI автоматически.
|
|
||||||
|
|
||||||
# chore(repo): нормализация EOL к LF + .gitattributes
|
|
||||||
26888a07d58351755fb8e487727c00d5b611eb95
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# EOL policy
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
|
||||||
# Авторский контент нормализуем к LF: инструмент правки (Edit) всегда пишет LF,
|
|
||||||
# поэтому единый LF убирает EOL-шум в диффах и ловушку «не правь CRLF-файл».
|
|
||||||
# git с eol=lf конвертит ТОЛЬКО CR<->LF и не трогает BOM (BOM — байты контента),
|
|
||||||
# поэтому BOM на .ps1 сохраняется.
|
|
||||||
*.ps1 text eol=lf
|
|
||||||
*.psm1 text eol=lf
|
|
||||||
*.py text eol=lf
|
|
||||||
*.mjs text eol=lf
|
|
||||||
*.md text eol=lf
|
|
||||||
*.json text eol=lf
|
|
||||||
.gitignore text eol=lf
|
|
||||||
|
|
||||||
# .bsl уже целиком LF — пин фиксирует статус-кво от будущего дрейфа.
|
|
||||||
*.bsl text eol=lf
|
|
||||||
|
|
||||||
# Данные 1С НЕ трогаем. *.xml — реальные выгрузки 1С (EOL местами значим,
|
|
||||||
# правим не мы, а навыки): оставляем как есть, под управление не берём.
|
|
||||||
# autocrlf=false и отсутствие text-атрибута => git хранит их байты как есть.
|
|
||||||
|
|
||||||
# Бинарники 1С
|
|
||||||
*.bin binary
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# 1C Skills for {{PLATFORM_LABEL}} ({{RUNTIME_LABEL}})
|
|
||||||
|
|
||||||
Автоматическая сборка из [main]({{MAIN_REPO_URL}}) — навыки 1С:Предприятие 8.3 для AI-агента **{{PLATFORM_LABEL}}** с рантаймом **{{RUNTIME_LABEL}}**.
|
|
||||||
|
|
||||||
> Эта ветка генерируется CI на каждый push в main. **Не редактируйте напрямую** — все правки идут в [main]({{MAIN_REPO_URL}}).
|
|
||||||
|
|
||||||
## Установка
|
|
||||||
|
|
||||||
1. Скачайте ZIP этой ветки: **Code → Download ZIP** (или `git archive`).
|
|
||||||
2. Распакуйте в корень своего проекта — должна появиться папка `{{PLATFORM_DIR}}/`.
|
|
||||||
3. Запустите {{PLATFORM_LABEL}} из этого проекта — навыки станут доступны.
|
|
||||||
|
|
||||||
## Требования
|
|
||||||
|
|
||||||
- **Windows** с PowerShell 5.1+ (входит в Windows) — для PowerShell-сборки.
|
|
||||||
- **Python 3.10+** — для Python-сборки. Зависимости: `lxml>=4.9.0`, `psutil>=5.9.0` (для DOM- и web-навыков).
|
|
||||||
- **1С:Предприятие 8.3** — для сборки/разборки EPF/ERF и работы с базами.
|
|
||||||
- **Node.js 18+** — для `/web-test`.
|
|
||||||
|
|
||||||
## Документация
|
|
||||||
|
|
||||||
Полные гайды, спецификации и описание навыков — в [main]({{MAIN_REPO_URL}}).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Source: {{MAIN_REPO_URL}}
|
|
||||||
Build commit: `{{COMMIT_SHA}}`
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
||||||
"name": "{{PLUGIN_NAME}}",
|
|
||||||
"description": "[Python] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент. Linux/Mac или когда PowerShell недоступен.",
|
|
||||||
"author": {
|
|
||||||
"name": "Nikolay Shirokov"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/Nikolay-Shirokov/cc-1c-skills",
|
|
||||||
"repository": "https://github.com/Nikolay-Shirokov/cc-1c-skills",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"1c",
|
|
||||||
"1c-dev",
|
|
||||||
"cf",
|
|
||||||
"cfe",
|
|
||||||
"epf",
|
|
||||||
"erf",
|
|
||||||
"metadata",
|
|
||||||
"configuration",
|
|
||||||
"extension",
|
|
||||||
"form",
|
|
||||||
"report",
|
|
||||||
"skd",
|
|
||||||
"data-processor",
|
|
||||||
"mxl",
|
|
||||||
"web-client",
|
|
||||||
"testing",
|
|
||||||
"test-automation"
|
|
||||||
],
|
|
||||||
"skills": "./.claude/skills/"
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "{{PLUGIN_NAME}}",
|
|
||||||
"version": "{{VERSION}}",
|
|
||||||
"description": "[{{RUNTIME_LABEL}}] Навыки для разработки на 1С:Предприятие 8.3 — абстракции над XML-форматами и CLI конфигуратора, плюс глаза и руки для тестирования через веб-клиент.",
|
|
||||||
"author": {
|
|
||||||
"name": "Nikolay Shirokov"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/Nikolay-Shirokov/cc-1c-skills",
|
|
||||||
"repository": "https://github.com/Nikolay-Shirokov/cc-1c-skills",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"1c",
|
|
||||||
"1c-dev",
|
|
||||||
"cf",
|
|
||||||
"cfe",
|
|
||||||
"epf",
|
|
||||||
"erf",
|
|
||||||
"metadata",
|
|
||||||
"configuration",
|
|
||||||
"extension",
|
|
||||||
"form",
|
|
||||||
"report",
|
|
||||||
"skd",
|
|
||||||
"data-processor",
|
|
||||||
"mxl",
|
|
||||||
"web-client",
|
|
||||||
"testing",
|
|
||||||
"test-automation"
|
|
||||||
],
|
|
||||||
"skills": "./.codex/skills/",
|
|
||||||
"interface": {
|
|
||||||
"displayName": "1C Skills ({{RUNTIME_LABEL}})",
|
|
||||||
"shortDescription": "{{SHORT_DESCRIPTION}}",
|
|
||||||
"category": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
name: Build port branches
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
paths:
|
|
||||||
- '.claude/skills/**'
|
|
||||||
- 'scripts/switch.py'
|
|
||||||
- '.github/templates/README.port.md.tmpl'
|
|
||||||
- '.github/templates/codex-plugin.json.tmpl'
|
|
||||||
- '.github/templates/claude-plugin.json.tmpl'
|
|
||||||
- '.github/workflows/build-ports.yml'
|
|
||||||
- 'LICENSE'
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- platform: claude-code
|
|
||||||
runtime: python
|
|
||||||
branch: port-claude-code-py
|
|
||||||
label: Claude Code
|
|
||||||
target_dir: .claude/skills
|
|
||||||
- platform: cursor
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-cursor
|
|
||||||
label: Cursor
|
|
||||||
target_dir: .cursor/skills
|
|
||||||
- platform: cursor
|
|
||||||
runtime: python
|
|
||||||
branch: port-cursor-py
|
|
||||||
label: Cursor
|
|
||||||
target_dir: .cursor/skills
|
|
||||||
- platform: codex
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-codex
|
|
||||||
label: Codex
|
|
||||||
target_dir: .codex/skills
|
|
||||||
- platform: codex
|
|
||||||
runtime: python
|
|
||||||
branch: port-codex-py
|
|
||||||
label: Codex
|
|
||||||
target_dir: .codex/skills
|
|
||||||
- platform: copilot
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-copilot
|
|
||||||
label: GitHub Copilot
|
|
||||||
target_dir: .github/skills
|
|
||||||
- platform: copilot
|
|
||||||
runtime: python
|
|
||||||
branch: port-copilot-py
|
|
||||||
label: GitHub Copilot
|
|
||||||
target_dir: .github/skills
|
|
||||||
- platform: augment
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-augment
|
|
||||||
label: Augment
|
|
||||||
target_dir: .augment/skills
|
|
||||||
- platform: augment
|
|
||||||
runtime: python
|
|
||||||
branch: port-augment-py
|
|
||||||
label: Augment
|
|
||||||
target_dir: .augment/skills
|
|
||||||
- platform: cline
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-cline
|
|
||||||
label: Cline
|
|
||||||
target_dir: .cline/skills
|
|
||||||
- platform: cline
|
|
||||||
runtime: python
|
|
||||||
branch: port-cline-py
|
|
||||||
label: Cline
|
|
||||||
target_dir: .cline/skills
|
|
||||||
- platform: kilo
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-kilo
|
|
||||||
label: Kilo Code
|
|
||||||
target_dir: .kilocode/skills
|
|
||||||
- platform: kilo
|
|
||||||
runtime: python
|
|
||||||
branch: port-kilo-py
|
|
||||||
label: Kilo Code
|
|
||||||
target_dir: .kilocode/skills
|
|
||||||
- platform: kiro
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-kiro
|
|
||||||
label: Kiro
|
|
||||||
target_dir: .kiro/skills
|
|
||||||
- platform: kiro
|
|
||||||
runtime: python
|
|
||||||
branch: port-kiro-py
|
|
||||||
label: Kiro
|
|
||||||
target_dir: .kiro/skills
|
|
||||||
- platform: gemini
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-gemini
|
|
||||||
label: Gemini CLI
|
|
||||||
target_dir: .gemini/skills
|
|
||||||
- platform: gemini
|
|
||||||
runtime: python
|
|
||||||
branch: port-gemini-py
|
|
||||||
label: Gemini CLI
|
|
||||||
target_dir: .gemini/skills
|
|
||||||
- platform: opencode
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-opencode
|
|
||||||
label: OpenCode
|
|
||||||
target_dir: .opencode/skills
|
|
||||||
- platform: opencode
|
|
||||||
runtime: python
|
|
||||||
branch: port-opencode-py
|
|
||||||
label: OpenCode
|
|
||||||
target_dir: .opencode/skills
|
|
||||||
- platform: roo
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-roo
|
|
||||||
label: Roo Code
|
|
||||||
target_dir: .roo/skills
|
|
||||||
- platform: roo
|
|
||||||
runtime: python
|
|
||||||
branch: port-roo-py
|
|
||||||
label: Roo Code
|
|
||||||
target_dir: .roo/skills
|
|
||||||
- platform: windsurf
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-windsurf
|
|
||||||
label: Windsurf
|
|
||||||
target_dir: .windsurf/skills
|
|
||||||
- platform: windsurf
|
|
||||||
runtime: python
|
|
||||||
branch: port-windsurf-py
|
|
||||||
label: Windsurf
|
|
||||||
target_dir: .windsurf/skills
|
|
||||||
- platform: codeassistant
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-codeassistant
|
|
||||||
label: Yandex Code Assistant
|
|
||||||
target_dir: .codeassistant/skills
|
|
||||||
- platform: codeassistant
|
|
||||||
runtime: python
|
|
||||||
branch: port-codeassistant-py
|
|
||||||
label: Yandex Code Assistant
|
|
||||||
target_dir: .codeassistant/skills
|
|
||||||
- platform: agents
|
|
||||||
runtime: powershell
|
|
||||||
branch: port-agents
|
|
||||||
label: Agent Skills
|
|
||||||
target_dir: .agents/skills
|
|
||||||
- platform: agents
|
|
||||||
runtime: python
|
|
||||||
branch: port-agents-py
|
|
||||||
label: Agent Skills
|
|
||||||
target_dir: .agents/skills
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout main
|
|
||||||
uses: actions/checkout@v5
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v6
|
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
|
|
||||||
- name: Build skills tree for ${{ matrix.platform }} (${{ matrix.runtime }})
|
|
||||||
run: |
|
|
||||||
python scripts/switch.py "${{ matrix.platform }}" \
|
|
||||||
--project-dir build \
|
|
||||||
--runtime "${{ matrix.runtime }}"
|
|
||||||
|
|
||||||
- name: Render port README
|
|
||||||
env:
|
|
||||||
PLATFORM_LABEL: ${{ matrix.label }}
|
|
||||||
PLATFORM_DIR: ${{ matrix.target_dir }}
|
|
||||||
RUNTIME_LABEL: ${{ matrix.runtime == 'powershell' && 'PowerShell' || 'Python' }}
|
|
||||||
COMMIT_SHA: ${{ github.sha }}
|
|
||||||
MAIN_REPO_URL: https://github.com/${{ github.repository }}
|
|
||||||
run: |
|
|
||||||
sed \
|
|
||||||
-e "s|{{PLATFORM_LABEL}}|${PLATFORM_LABEL}|g" \
|
|
||||||
-e "s|{{PLATFORM_DIR}}|${PLATFORM_DIR}|g" \
|
|
||||||
-e "s|{{RUNTIME_LABEL}}|${RUNTIME_LABEL}|g" \
|
|
||||||
-e "s|{{COMMIT_SHA}}|${COMMIT_SHA}|g" \
|
|
||||||
-e "s|{{MAIN_REPO_URL}}|${MAIN_REPO_URL}|g" \
|
|
||||||
.github/templates/README.port.md.tmpl > build/README.md
|
|
||||||
|
|
||||||
- name: Render Codex plugin manifest
|
|
||||||
if: matrix.platform == 'codex'
|
|
||||||
env:
|
|
||||||
PLUGIN_NAME: ${{ matrix.runtime == 'python' && '1c-skills-py' || '1c-skills' }}
|
|
||||||
RUNTIME_LABEL: ${{ matrix.runtime == 'powershell' && 'PowerShell' || 'Python' }}
|
|
||||||
SHORT_DESCRIPTION: ${{ matrix.runtime == 'python' && 'Python runtime (Linux/Mac/Windows)' || 'PowerShell runtime (Windows-first)' }}
|
|
||||||
COMMIT_SHA: ${{ github.sha }}
|
|
||||||
run: |
|
|
||||||
VERSION="$(date -u +%Y.%-m.%-d)+${COMMIT_SHA::7}"
|
|
||||||
mkdir -p build/.codex-plugin
|
|
||||||
sed \
|
|
||||||
-e "s|{{PLUGIN_NAME}}|${PLUGIN_NAME}|g" \
|
|
||||||
-e "s|{{VERSION}}|${VERSION}|g" \
|
|
||||||
-e "s|{{RUNTIME_LABEL}}|${RUNTIME_LABEL}|g" \
|
|
||||||
-e "s|{{SHORT_DESCRIPTION}}|${SHORT_DESCRIPTION}|g" \
|
|
||||||
.github/templates/codex-plugin.json.tmpl > build/.codex-plugin/plugin.json
|
|
||||||
|
|
||||||
- name: Render Claude plugin manifest (Py variant)
|
|
||||||
if: matrix.platform == 'claude-code' && matrix.runtime == 'python'
|
|
||||||
env:
|
|
||||||
PLUGIN_NAME: 1c-skills-py
|
|
||||||
run: |
|
|
||||||
mkdir -p build/.claude-plugin
|
|
||||||
sed -e "s|{{PLUGIN_NAME}}|${PLUGIN_NAME}|g" \
|
|
||||||
.github/templates/claude-plugin.json.tmpl > build/.claude-plugin/plugin.json
|
|
||||||
|
|
||||||
- name: Copy LICENSE
|
|
||||||
run: cp LICENSE build/LICENSE
|
|
||||||
|
|
||||||
- name: Force-push orphan snapshot to ${{ matrix.branch }}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
cd build
|
|
||||||
git init -q -b master
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
git add -A
|
|
||||||
git commit -q -m "Auto-build: ${{ matrix.platform }} (${{ matrix.runtime }}) from ${GITHUB_SHA::7}"
|
|
||||||
git push --force \
|
|
||||||
"https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" \
|
|
||||||
"master:${{ matrix.branch }}"
|
|
||||||
-52
@@ -1,52 +0,0 @@
|
|||||||
# Реальные выгрузки обработок (примеры, не для версионирования)
|
|
||||||
upload/
|
|
||||||
|
|
||||||
# Результаты сборки
|
|
||||||
build/
|
|
||||||
base/
|
|
||||||
*.epf
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Временные файлы тестов
|
|
||||||
test-tmp/
|
|
||||||
|
|
||||||
# Локальные настройки Claude Code
|
|
||||||
.claude/settings.local.json
|
|
||||||
|
|
||||||
# Инструменты (portable Apache и т.д.)
|
|
||||||
tools/
|
|
||||||
|
|
||||||
# Отладка навыков (eval, trigger-test, run_loop результаты)
|
|
||||||
debug/
|
|
||||||
|
|
||||||
# Кэш тестов навыков
|
|
||||||
tests/skills/.cache/
|
|
||||||
|
|
||||||
# Python кэш
|
|
||||||
__pycache__/
|
|
||||||
|
|
||||||
# Локальный реестр баз данных 1С
|
|
||||||
.v8-project.json
|
|
||||||
|
|
||||||
# web-test: Node.js зависимости и runtime-артефакты
|
|
||||||
.claude/skills/web-test/scripts/node_modules/
|
|
||||||
.claude/skills/web-test/.browser-session.json
|
|
||||||
|
|
||||||
# Скриншоты и видео (артефакты тестирования web-test)
|
|
||||||
*.png
|
|
||||||
*.mp4
|
|
||||||
|
|
||||||
# Навыки, скопированные для других AI-платформ (генерируются scripts/switch.py)
|
|
||||||
.agents/skills/
|
|
||||||
.augment/
|
|
||||||
.cline/
|
|
||||||
.codex/
|
|
||||||
.cursor/
|
|
||||||
.gemini/
|
|
||||||
.github/skills/
|
|
||||||
.kilocode/
|
|
||||||
.kiro/
|
|
||||||
.opencode/
|
|
||||||
.roo/
|
|
||||||
.windsurf/
|
|
||||||
debug-templates.txt
|
|
||||||
@@ -24,7 +24,7 @@ allowed-tools:
|
|||||||
| `NoValidate` | Пропустить авто-валидацию |
|
| `NoValidate` | Пропустить авто-валидацию |
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-edit.ps1" -ConfigPath '<path>' -Operation modify-property -Value 'Version=1.0.0.1'
|
python ".opencode/skills/cf-edit/scripts/cf-edit.py" -ConfigPath '<path>' -Operation modify-property -Value 'Version=1.0.0.1'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Операции
|
## Операции
|
||||||
+4
-3
@@ -1,4 +1,4 @@
|
|||||||
# cf-edit v1.7 — Edit 1C configuration root (Configuration.xml)
|
# cf-edit v1.8 — Edit 1C configuration root (Configuration.xml)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)][Alias('Path')][string]$ConfigPath,
|
[Parameter(Mandatory)][Alias('Path')][string]$ConfigPath,
|
||||||
@@ -196,7 +196,7 @@ Info "Configuration: $($script:objName)"
|
|||||||
$script:typeOrder = @(
|
$script:typeOrder = @(
|
||||||
"Language","Subsystem","StyleItem","Style",
|
"Language","Subsystem","StyleItem","Style",
|
||||||
"CommonPicture","SessionParameter","Role","CommonTemplate",
|
"CommonPicture","SessionParameter","Role","CommonTemplate",
|
||||||
"FilterCriterion","CommonModule","CommonAttribute","ExchangePlan",
|
"FilterCriterion","CommonModule","Bot","CommonAttribute","ExchangePlan",
|
||||||
"XDTOPackage","WebService","HTTPService","WSReference",
|
"XDTOPackage","WebService","HTTPService","WSReference",
|
||||||
"EventSubscription","ScheduledJob","SettingsStorage","FunctionalOption",
|
"EventSubscription","ScheduledJob","SettingsStorage","FunctionalOption",
|
||||||
"FunctionalOptionsParameter","DefinedType","CommonCommand","CommandGroup",
|
"FunctionalOptionsParameter","DefinedType","CommonCommand","CommandGroup",
|
||||||
@@ -212,7 +212,7 @@ $script:typeOrder = @(
|
|||||||
$script:typeToDir = @{
|
$script:typeToDir = @{
|
||||||
"Language"="Languages"; "Subsystem"="Subsystems"; "StyleItem"="StyleItems"; "Style"="Styles"
|
"Language"="Languages"; "Subsystem"="Subsystems"; "StyleItem"="StyleItems"; "Style"="Styles"
|
||||||
"CommonPicture"="CommonPictures"; "SessionParameter"="SessionParameters"; "Role"="Roles"; "CommonTemplate"="CommonTemplates"
|
"CommonPicture"="CommonPictures"; "SessionParameter"="SessionParameters"; "Role"="Roles"; "CommonTemplate"="CommonTemplates"
|
||||||
"FilterCriterion"="FilterCriteria"; "CommonModule"="CommonModules"; "CommonAttribute"="CommonAttributes"; "ExchangePlan"="ExchangePlans"
|
"FilterCriterion"="FilterCriteria"; "CommonModule"="CommonModules"; "Bot"="Bots"; "CommonAttribute"="CommonAttributes"; "ExchangePlan"="ExchangePlans"
|
||||||
"XDTOPackage"="XDTOPackages"; "WebService"="WebServices"; "HTTPService"="HTTPServices"; "WSReference"="WSReferences"
|
"XDTOPackage"="XDTOPackages"; "WebService"="WebServices"; "HTTPService"="HTTPServices"; "WSReference"="WSReferences"
|
||||||
"EventSubscription"="EventSubscriptions"; "ScheduledJob"="ScheduledJobs"; "SettingsStorage"="SettingsStorages"; "FunctionalOption"="FunctionalOptions"
|
"EventSubscription"="EventSubscriptions"; "ScheduledJob"="ScheduledJobs"; "SettingsStorage"="SettingsStorages"; "FunctionalOption"="FunctionalOptions"
|
||||||
"FunctionalOptionsParameter"="FunctionalOptionsParameters"; "DefinedType"="DefinedTypes"; "CommonCommand"="CommonCommands"; "CommandGroup"="CommandGroups"
|
"FunctionalOptionsParameter"="FunctionalOptionsParameters"; "DefinedType"="DefinedTypes"; "CommonCommand"="CommonCommands"; "CommandGroup"="CommandGroups"
|
||||||
@@ -700,6 +700,7 @@ $script:ruTypeMap = @{
|
|||||||
"регистррасчёта" = "CalculationRegister"
|
"регистррасчёта" = "CalculationRegister"
|
||||||
"бизнеспроцесс" = "BusinessProcess"
|
"бизнеспроцесс" = "BusinessProcess"
|
||||||
"задача" = "Task"
|
"задача" = "Task"
|
||||||
|
"бот" = "Bot"
|
||||||
"планобмена" = "ExchangePlan"
|
"планобмена" = "ExchangePlan"
|
||||||
"хранилищенастроек" = "SettingsStorage"
|
"хранилищенастроек" = "SettingsStorage"
|
||||||
}
|
}
|
||||||
+4
-3
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# cf-edit v1.7 — Edit 1C configuration root (Configuration.xml)
|
# cf-edit v1.8 — Edit 1C configuration root (Configuration.xml)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -182,7 +182,7 @@ XS_NS = "http://www.w3.org/2001/XMLSchema"
|
|||||||
TYPE_ORDER = [
|
TYPE_ORDER = [
|
||||||
"Language", "Subsystem", "StyleItem", "Style",
|
"Language", "Subsystem", "StyleItem", "Style",
|
||||||
"CommonPicture", "SessionParameter", "Role", "CommonTemplate",
|
"CommonPicture", "SessionParameter", "Role", "CommonTemplate",
|
||||||
"FilterCriterion", "CommonModule", "CommonAttribute", "ExchangePlan",
|
"FilterCriterion", "CommonModule", "Bot", "CommonAttribute", "ExchangePlan",
|
||||||
"XDTOPackage", "WebService", "HTTPService", "WSReference",
|
"XDTOPackage", "WebService", "HTTPService", "WSReference",
|
||||||
"EventSubscription", "ScheduledJob", "SettingsStorage", "FunctionalOption",
|
"EventSubscription", "ScheduledJob", "SettingsStorage", "FunctionalOption",
|
||||||
"FunctionalOptionsParameter", "DefinedType", "CommonCommand", "CommandGroup",
|
"FunctionalOptionsParameter", "DefinedType", "CommonCommand", "CommandGroup",
|
||||||
@@ -198,7 +198,7 @@ TYPE_ORDER = [
|
|||||||
TYPE_TO_DIR = {
|
TYPE_TO_DIR = {
|
||||||
"Language": "Languages", "Subsystem": "Subsystems", "StyleItem": "StyleItems", "Style": "Styles",
|
"Language": "Languages", "Subsystem": "Subsystems", "StyleItem": "StyleItems", "Style": "Styles",
|
||||||
"CommonPicture": "CommonPictures", "SessionParameter": "SessionParameters", "Role": "Roles", "CommonTemplate": "CommonTemplates",
|
"CommonPicture": "CommonPictures", "SessionParameter": "SessionParameters", "Role": "Roles", "CommonTemplate": "CommonTemplates",
|
||||||
"FilterCriterion": "FilterCriteria", "CommonModule": "CommonModules", "CommonAttribute": "CommonAttributes", "ExchangePlan": "ExchangePlans",
|
"FilterCriterion": "FilterCriteria", "CommonModule": "CommonModules", "Bot": "Bots", "CommonAttribute": "CommonAttributes", "ExchangePlan": "ExchangePlans",
|
||||||
"XDTOPackage": "XDTOPackages", "WebService": "WebServices", "HTTPService": "HTTPServices", "WSReference": "WSReferences",
|
"XDTOPackage": "XDTOPackages", "WebService": "WebServices", "HTTPService": "HTTPServices", "WSReference": "WSReferences",
|
||||||
"EventSubscription": "EventSubscriptions", "ScheduledJob": "ScheduledJobs", "SettingsStorage": "SettingsStorages", "FunctionalOption": "FunctionalOptions",
|
"EventSubscription": "EventSubscriptions", "ScheduledJob": "ScheduledJobs", "SettingsStorage": "SettingsStorages", "FunctionalOption": "FunctionalOptions",
|
||||||
"FunctionalOptionsParameter": "FunctionalOptionsParameters", "DefinedType": "DefinedTypes", "CommonCommand": "CommonCommands", "CommandGroup": "CommandGroups",
|
"FunctionalOptionsParameter": "FunctionalOptionsParameters", "DefinedType": "DefinedTypes", "CommonCommand": "CommonCommands", "CommandGroup": "CommandGroups",
|
||||||
@@ -771,6 +771,7 @@ def main():
|
|||||||
"регистррасчета": "CalculationRegister",
|
"регистррасчета": "CalculationRegister",
|
||||||
"регистррасчёта": "CalculationRegister",
|
"регистррасчёта": "CalculationRegister",
|
||||||
"бизнеспроцесс": "BusinessProcess",
|
"бизнеспроцесс": "BusinessProcess",
|
||||||
|
"бот": "Bot",
|
||||||
"задача": "Task", "планобмена": "ExchangePlan",
|
"задача": "Task", "планобмена": "ExchangePlan",
|
||||||
"хранилищенастроек": "SettingsStorage",
|
"хранилищенастроек": "SettingsStorage",
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ allowed-tools:
|
|||||||
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
|
| `OutFile` | Записать результат в файл (UTF-8 BOM) |
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-info.ps1" -ConfigPath "<путь>"
|
python ".opencode/skills/cf-info/scripts/cf-info.py" -ConfigPath "<путь>"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Три режима
|
## Три режима
|
||||||
+3
-2
@@ -1,4 +1,4 @@
|
|||||||
# cf-info v1.3 — Compact summary of 1C configuration root
|
# cf-info v1.4 — Compact summary of 1C configuration root
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory=$true)][Alias('Path')][string]$ConfigPath,
|
[Parameter(Mandatory=$true)][Alias('Path')][string]$ConfigPath,
|
||||||
@@ -89,7 +89,7 @@ function Get-PropML([string]$propName) {
|
|||||||
$typeOrder = @(
|
$typeOrder = @(
|
||||||
"Language","Subsystem","StyleItem","Style",
|
"Language","Subsystem","StyleItem","Style",
|
||||||
"CommonPicture","SessionParameter","Role","CommonTemplate",
|
"CommonPicture","SessionParameter","Role","CommonTemplate",
|
||||||
"FilterCriterion","CommonModule","CommonAttribute","ExchangePlan",
|
"FilterCriterion","CommonModule","Bot","CommonAttribute","ExchangePlan",
|
||||||
"XDTOPackage","WebService","HTTPService","WSReference",
|
"XDTOPackage","WebService","HTTPService","WSReference",
|
||||||
"EventSubscription","ScheduledJob","SettingsStorage","FunctionalOption",
|
"EventSubscription","ScheduledJob","SettingsStorage","FunctionalOption",
|
||||||
"FunctionalOptionsParameter","DefinedType","CommonCommand","CommandGroup",
|
"FunctionalOptionsParameter","DefinedType","CommonCommand","CommandGroup",
|
||||||
@@ -105,6 +105,7 @@ $typeRuNames = @{
|
|||||||
"Language"="Языки"; "Subsystem"="Подсистемы"; "StyleItem"="Элементы стиля"; "Style"="Стили"
|
"Language"="Языки"; "Subsystem"="Подсистемы"; "StyleItem"="Элементы стиля"; "Style"="Стили"
|
||||||
"CommonPicture"="Общие картинки"; "SessionParameter"="Параметры сеанса"; "Role"="Роли"
|
"CommonPicture"="Общие картинки"; "SessionParameter"="Параметры сеанса"; "Role"="Роли"
|
||||||
"CommonTemplate"="Общие макеты"; "FilterCriterion"="Критерии отбора"; "CommonModule"="Общие модули"
|
"CommonTemplate"="Общие макеты"; "FilterCriterion"="Критерии отбора"; "CommonModule"="Общие модули"
|
||||||
|
"Bot"="Боты"
|
||||||
"CommonAttribute"="Общие реквизиты"; "ExchangePlan"="Планы обмена"; "XDTOPackage"="XDTO-пакеты"
|
"CommonAttribute"="Общие реквизиты"; "ExchangePlan"="Планы обмена"; "XDTOPackage"="XDTO-пакеты"
|
||||||
"WebService"="Веб-сервисы"; "HTTPService"="HTTP-сервисы"; "WSReference"="WS-ссылки"
|
"WebService"="Веб-сервисы"; "HTTPService"="HTTP-сервисы"; "WSReference"="WS-ссылки"
|
||||||
"EventSubscription"="Подписки на события"; "ScheduledJob"="Регламентные задания"
|
"EventSubscription"="Подписки на события"; "ScheduledJob"="Регламентные задания"
|
||||||
+3
-2
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# cf-info v1.3 — Compact summary of 1C configuration root
|
# cf-info v1.4 — Compact summary of 1C configuration root
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -95,7 +95,7 @@ def get_prop_ml(prop_name):
|
|||||||
type_order = [
|
type_order = [
|
||||||
"Language", "Subsystem", "StyleItem", "Style",
|
"Language", "Subsystem", "StyleItem", "Style",
|
||||||
"CommonPicture", "SessionParameter", "Role", "CommonTemplate",
|
"CommonPicture", "SessionParameter", "Role", "CommonTemplate",
|
||||||
"FilterCriterion", "CommonModule", "CommonAttribute", "ExchangePlan",
|
"FilterCriterion", "CommonModule", "Bot", "CommonAttribute", "ExchangePlan",
|
||||||
"XDTOPackage", "WebService", "HTTPService", "WSReference",
|
"XDTOPackage", "WebService", "HTTPService", "WSReference",
|
||||||
"EventSubscription", "ScheduledJob", "SettingsStorage", "FunctionalOption",
|
"EventSubscription", "ScheduledJob", "SettingsStorage", "FunctionalOption",
|
||||||
"FunctionalOptionsParameter", "DefinedType", "CommonCommand", "CommandGroup",
|
"FunctionalOptionsParameter", "DefinedType", "CommonCommand", "CommandGroup",
|
||||||
@@ -111,6 +111,7 @@ type_ru_names = {
|
|||||||
"Language": "Языки", "Subsystem": "Подсистемы", "StyleItem": "Элементы стиля", "Style": "Стили",
|
"Language": "Языки", "Subsystem": "Подсистемы", "StyleItem": "Элементы стиля", "Style": "Стили",
|
||||||
"CommonPicture": "Общие картинки", "SessionParameter": "Параметры сеанса", "Role": "Роли",
|
"CommonPicture": "Общие картинки", "SessionParameter": "Параметры сеанса", "Role": "Роли",
|
||||||
"CommonTemplate": "Общие макеты", "FilterCriterion": "Критерии отбора", "CommonModule": "Общие модули",
|
"CommonTemplate": "Общие макеты", "FilterCriterion": "Критерии отбора", "CommonModule": "Общие модули",
|
||||||
|
"Bot": "Боты",
|
||||||
"CommonAttribute": "Общие реквизиты", "ExchangePlan": "Планы обмена", "XDTOPackage": "XDTO-пакеты",
|
"CommonAttribute": "Общие реквизиты", "ExchangePlan": "Планы обмена", "XDTOPackage": "XDTO-пакеты",
|
||||||
"WebService": "Веб-сервисы", "HTTPService": "HTTP-сервисы", "WSReference": "WS-ссылки",
|
"WebService": "Веб-сервисы", "HTTPService": "HTTP-сервисы", "WSReference": "WS-ссылки",
|
||||||
"EventSubscription": "Подписки на события", "ScheduledJob": "Регламентные задания",
|
"EventSubscription": "Подписки на события", "ScheduledJob": "Регламентные задания",
|
||||||
@@ -24,7 +24,7 @@ allowed-tools:
|
|||||||
| `CompatibilityMode` | Режим совместимости (default: `Version8_3_24`) |
|
| `CompatibilityMode` | Режим совместимости (default: `Version8_3_24`) |
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-init.ps1" -Name "МояКонфигурация"
|
python ".opencode/skills/cf-init/scripts/cf-init.py" -Name "МояКонфигурация"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Примеры
|
## Примеры
|
||||||
@@ -24,6 +24,6 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-validate.ps1" -ConfigPath "upload/cfempty"
|
python ".opencode/skills/cf-validate/scripts/cf-validate.py" -ConfigPath "upload/cfempty"
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cf-validate.ps1" -ConfigPath "upload/cfempty/Configuration.xml"
|
python ".opencode/skills/cf-validate/scripts/cf-validate.py" -ConfigPath "upload/cfempty/Configuration.xml"
|
||||||
```
|
```
|
||||||
+4
-3
@@ -1,4 +1,4 @@
|
|||||||
# cf-validate v1.3 — Validate 1C configuration root structure
|
# cf-validate v1.4 — Validate 1C configuration root structure
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -104,11 +104,11 @@ $validClassIds = @(
|
|||||||
"fb282519-d103-4dd3-bc12-cb271d631dfc" # home page / client app interface
|
"fb282519-d103-4dd3-bc12-cb271d631dfc" # home page / client app interface
|
||||||
)
|
)
|
||||||
|
|
||||||
# 44 types in canonical order
|
# 45 types in canonical order
|
||||||
$childObjectTypes = @(
|
$childObjectTypes = @(
|
||||||
"Language","Subsystem","StyleItem","Style",
|
"Language","Subsystem","StyleItem","Style",
|
||||||
"CommonPicture","SessionParameter","Role","CommonTemplate",
|
"CommonPicture","SessionParameter","Role","CommonTemplate",
|
||||||
"FilterCriterion","CommonModule","CommonAttribute","ExchangePlan",
|
"FilterCriterion","CommonModule","Bot","CommonAttribute","ExchangePlan",
|
||||||
"XDTOPackage","WebService","HTTPService","WSReference",
|
"XDTOPackage","WebService","HTTPService","WSReference",
|
||||||
"EventSubscription","ScheduledJob","SettingsStorage","FunctionalOption",
|
"EventSubscription","ScheduledJob","SettingsStorage","FunctionalOption",
|
||||||
"FunctionalOptionsParameter","DefinedType","CommonCommand","CommandGroup",
|
"FunctionalOptionsParameter","DefinedType","CommonCommand","CommandGroup",
|
||||||
@@ -125,6 +125,7 @@ $childTypeDirMap = @{
|
|||||||
"Language"="Languages"; "Subsystem"="Subsystems"; "StyleItem"="StyleItems"; "Style"="Styles"
|
"Language"="Languages"; "Subsystem"="Subsystems"; "StyleItem"="StyleItems"; "Style"="Styles"
|
||||||
"CommonPicture"="CommonPictures"; "SessionParameter"="SessionParameters"; "Role"="Roles"
|
"CommonPicture"="CommonPictures"; "SessionParameter"="SessionParameters"; "Role"="Roles"
|
||||||
"CommonTemplate"="CommonTemplates"; "FilterCriterion"="FilterCriteria"; "CommonModule"="CommonModules"
|
"CommonTemplate"="CommonTemplates"; "FilterCriterion"="FilterCriteria"; "CommonModule"="CommonModules"
|
||||||
|
"Bot"="Bots"
|
||||||
"CommonAttribute"="CommonAttributes"; "ExchangePlan"="ExchangePlans"; "XDTOPackage"="XDTOPackages"
|
"CommonAttribute"="CommonAttributes"; "ExchangePlan"="ExchangePlans"; "XDTOPackage"="XDTOPackages"
|
||||||
"WebService"="WebServices"; "HTTPService"="HTTPServices"; "WSReference"="WSReferences"
|
"WebService"="WebServices"; "HTTPService"="HTTPServices"; "WSReference"="WSReferences"
|
||||||
"EventSubscription"="EventSubscriptions"; "ScheduledJob"="ScheduledJobs"
|
"EventSubscription"="EventSubscriptions"; "ScheduledJob"="ScheduledJobs"
|
||||||
+4
-3
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# cf-validate v1.3 — Validate 1C configuration XML structure
|
# cf-validate v1.4 — Validate 1C configuration XML structure
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
"""Validates Configuration.xml: root structure, InternalInfo, properties, ChildObjects, languages."""
|
"""Validates Configuration.xml: root structure, InternalInfo, properties, ChildObjects, languages."""
|
||||||
import sys, os, argparse, re
|
import sys, os, argparse, re
|
||||||
@@ -33,11 +33,11 @@ VALID_CLASS_IDS = [
|
|||||||
'fb282519-d103-4dd3-bc12-cb271d631dfc', # home page / client app interface
|
'fb282519-d103-4dd3-bc12-cb271d631dfc', # home page / client app interface
|
||||||
]
|
]
|
||||||
|
|
||||||
# 44 types in canonical order
|
# 45 types in canonical order
|
||||||
CHILD_OBJECT_TYPES = [
|
CHILD_OBJECT_TYPES = [
|
||||||
'Language', 'Subsystem', 'StyleItem', 'Style',
|
'Language', 'Subsystem', 'StyleItem', 'Style',
|
||||||
'CommonPicture', 'SessionParameter', 'Role', 'CommonTemplate',
|
'CommonPicture', 'SessionParameter', 'Role', 'CommonTemplate',
|
||||||
'FilterCriterion', 'CommonModule', 'CommonAttribute', 'ExchangePlan',
|
'FilterCriterion', 'CommonModule', 'Bot', 'CommonAttribute', 'ExchangePlan',
|
||||||
'XDTOPackage', 'WebService', 'HTTPService', 'WSReference',
|
'XDTOPackage', 'WebService', 'HTTPService', 'WSReference',
|
||||||
'EventSubscription', 'ScheduledJob', 'SettingsStorage', 'FunctionalOption',
|
'EventSubscription', 'ScheduledJob', 'SettingsStorage', 'FunctionalOption',
|
||||||
'FunctionalOptionsParameter', 'DefinedType', 'CommonCommand', 'CommandGroup',
|
'FunctionalOptionsParameter', 'DefinedType', 'CommonCommand', 'CommandGroup',
|
||||||
@@ -54,6 +54,7 @@ CHILD_TYPE_DIR_MAP = {
|
|||||||
'Language': 'Languages', 'Subsystem': 'Subsystems', 'StyleItem': 'StyleItems', 'Style': 'Styles',
|
'Language': 'Languages', 'Subsystem': 'Subsystems', 'StyleItem': 'StyleItems', 'Style': 'Styles',
|
||||||
'CommonPicture': 'CommonPictures', 'SessionParameter': 'SessionParameters', 'Role': 'Roles',
|
'CommonPicture': 'CommonPictures', 'SessionParameter': 'SessionParameters', 'Role': 'Roles',
|
||||||
'CommonTemplate': 'CommonTemplates', 'FilterCriterion': 'FilterCriteria', 'CommonModule': 'CommonModules',
|
'CommonTemplate': 'CommonTemplates', 'FilterCriterion': 'FilterCriteria', 'CommonModule': 'CommonModules',
|
||||||
|
'Bot': 'Bots',
|
||||||
'CommonAttribute': 'CommonAttributes', 'ExchangePlan': 'ExchangePlans', 'XDTOPackage': 'XDTOPackages',
|
'CommonAttribute': 'CommonAttributes', 'ExchangePlan': 'ExchangePlans', 'XDTOPackage': 'XDTOPackages',
|
||||||
'WebService': 'WebServices', 'HTTPService': 'HTTPServices', 'WSReference': 'WSReferences',
|
'WebService': 'WebServices', 'HTTPService': 'HTTPServices', 'WSReference': 'WSReferences',
|
||||||
'EventSubscription': 'EventSubscriptions', 'ScheduledJob': 'ScheduledJobs',
|
'EventSubscription': 'EventSubscriptions', 'ScheduledJob': 'ScheduledJobs',
|
||||||
@@ -71,7 +71,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-borrow.ps1" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты"
|
python ".opencode/skills/cfe-borrow/scripts/cfe-borrow.py" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Object "Catalog.Контрагенты"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Примеры
|
## Примеры
|
||||||
@@ -23,7 +23,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-diff.ps1" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode A
|
python ".opencode/skills/cfe-diff/scripts/cfe-diff.py" -ExtensionPath src -ConfigPath C:\cfsrc\erp -Mode A
|
||||||
```
|
```
|
||||||
|
|
||||||
## Mode A — обзор расширения
|
## Mode A — обзор расширения
|
||||||
@@ -44,7 +44,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-init.ps1" -Name "МоёРасширение"
|
python ".opencode/skills/cfe-init/scripts/cfe-init.py" -Name "МоёРасширение"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Примеры
|
## Примеры
|
||||||
+1
-1
@@ -51,7 +51,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-patch-method.ps1" -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
|
python ".opencode/skills/cfe-patch-method/scripts/cfe-patch-method.py" -ExtensionPath src -ModulePath "Catalog.Контрагенты.ObjectModule" -MethodName "ПриЗаписи" -InterceptorType Before
|
||||||
```
|
```
|
||||||
|
|
||||||
## Примеры
|
## Примеры
|
||||||
@@ -24,6 +24,6 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.ps1" -ExtensionPath "src"
|
python ".opencode/skills/cfe-validate/scripts/cfe-validate.py" -ExtensionPath "src"
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/cfe-validate.ps1" -ExtensionPath "src/Configuration.xml"
|
python ".opencode/skills/cfe-validate/scripts/cfe-validate.py" -ExtensionPath "src/Configuration.xml"
|
||||||
```
|
```
|
||||||
@@ -31,7 +31,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" <параметры>
|
python ".opencode/skills/db-create/scripts/db-create.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -57,14 +57,14 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" <п
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Создать файловую базу
|
# Создать файловую базу
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBasePath "C:\Bases\NewDB"
|
python ".opencode/skills/db-create/scripts/db-create.py" -InfoBasePath "C:\Bases\NewDB"
|
||||||
|
|
||||||
# Создать серверную базу
|
# Создать серверную базу
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test"
|
python ".opencode/skills/db-create/scripts/db-create.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test"
|
||||||
|
|
||||||
# Создать из шаблона CF
|
# Создать из шаблона CF
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBasePath "C:\Bases\NewDB" -UseTemplate "C:\Templates\config.cf"
|
python ".opencode/skills/db-create/scripts/db-create.py" -InfoBasePath "C:\Bases\NewDB" -UseTemplate "C:\Templates\config.cf"
|
||||||
|
|
||||||
# Создать и добавить в список баз
|
# Создать и добавить в список баз
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-create.ps1" -InfoBasePath "C:\Bases\NewDB" -AddToList -ListName "Новая база"
|
python ".opencode/skills/db-create/scripts/db-create.py" -InfoBasePath "C:\Bases\NewDB" -AddToList -ListName "Новая база"
|
||||||
```
|
```
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# db-create v1.4 — Create 1C information base
|
# db-create v1.6 — Create 1C information base
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Создание информационной базы 1С
|
Создание информационной базы 1С
|
||||||
@@ -96,7 +97,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,11 +106,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -146,8 +174,9 @@ try {
|
|||||||
}
|
}
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Information base created successfully: $InfoBasePath" -ForegroundColor Green
|
Write-Host "Information base created successfully: $InfoBasePath" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-create v1.4 — Create 1C information base
|
# db-create v1.6 — Create 1C information base
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -111,7 +144,7 @@ def main():
|
|||||||
atexit.register(shutil.rmtree, ib_data, ignore_errors=True)
|
atexit.register(shutil.rmtree, ib_data, ignore_errors=True)
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, warn_no_user=False)
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"Information base created successfully: {args.InfoBasePath}")
|
print(f"Information base created successfully: {args.InfoBasePath}")
|
||||||
else:
|
else:
|
||||||
@@ -35,7 +35,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" <параметры>
|
python ".opencode/skills/db-dump-cf/scripts/db-dump-cf.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -58,11 +58,11 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" <п
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Выгрузка конфигурации (файловая база)
|
# Выгрузка конфигурации (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "C:\backup\config.cf"
|
python ".opencode/skills/db-dump-cf/scripts/db-dump-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "C:\backup\config.cf"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -OutputFile "config.cf"
|
python ".opencode/skills/db-dump-cf/scripts/db-dump-cf.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -OutputFile "config.cf"
|
||||||
|
|
||||||
# Выгрузка расширения
|
# Выгрузка расширения
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "ext.cfe" -Extension "МоёРасширение"
|
python ".opencode/skills/db-dump-cf/scripts/db-dump-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "ext.cfe" -Extension "МоёРасширение"
|
||||||
```
|
```
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# db-dump-cf v1.4 — Dump 1C configuration to CF file
|
# db-dump-cf v1.6 — Dump 1C configuration to CF file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Выгрузка конфигурации 1С в CF-файл
|
Выгрузка конфигурации 1С в CF-файл
|
||||||
@@ -105,7 +106,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,11 +115,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -156,8 +184,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Configuration dumped successfully to: $OutputFile" -ForegroundColor Green
|
Write-Host "Configuration dumped successfully to: $OutputFile" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-dump-cf v1.4 — Dump 1C configuration to CF file
|
# db-dump-cf v1.6 — Dump 1C configuration to CF file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -118,7 +151,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"Configuration dumped successfully to: {args.OutputFile}")
|
print(f"Configuration dumped successfully to: {args.OutputFile}")
|
||||||
else:
|
else:
|
||||||
@@ -38,7 +38,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <параметры>
|
python ".opencode/skills/db-dump-dt/scripts/db-dump-dt.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -59,10 +59,10 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" <п
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Выгрузка ИБ (файловая база)
|
# Выгрузка ИБ (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "C:\backup\base.dt"
|
python ".opencode/skills/db-dump-dt/scripts/db-dump-dt.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -OutputFile "C:\backup\base.dt"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-dt.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -OutputFile "base.dt"
|
python ".opencode/skills/db-dump-dt/scripts/db-dump-dt.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -OutputFile "base.dt"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Связанные навыки
|
## Связанные навыки
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# db-dump-dt v1.3 — Dump 1C information base to DT file
|
# db-dump-dt v1.5 — Dump 1C information base to DT file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Выгрузка информационной базы 1С в DT-файл
|
Выгрузка информационной базы 1С в DT-файл
|
||||||
@@ -89,7 +90,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,11 +99,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -136,8 +164,9 @@ try {
|
|||||||
|
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Information base dumped successfully to: $OutputFile" -ForegroundColor Green
|
Write-Host "Information base dumped successfully to: $OutputFile" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-dump-dt v1.3 — Dump 1C information base to DT file
|
# db-dump-dt v1.5 — Dump 1C information base to DT file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -111,7 +144,7 @@ def main():
|
|||||||
atexit.register(shutil.rmtree, ib_data, ignore_errors=True)
|
atexit.register(shutil.rmtree, ib_data, ignore_errors=True)
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"Information base dumped successfully to: {args.OutputFile}")
|
print(f"Information base dumped successfully to: {args.OutputFile}")
|
||||||
else:
|
else:
|
||||||
@@ -37,7 +37,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" <параметры>
|
python ".opencode/skills/db-dump-xml/scripts/db-dump-xml.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -74,17 +74,17 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" <
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Полная выгрузка (файловая база)
|
# Полная выгрузка (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
|
python ".opencode/skills/db-dump-xml/scripts/db-dump-xml.py" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
|
||||||
|
|
||||||
# Инкрементальная выгрузка
|
# Инкрементальная выгрузка
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Changes
|
python ".opencode/skills/db-dump-xml/scripts/db-dump-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Changes
|
||||||
|
|
||||||
# Частичная выгрузка
|
# Частичная выгрузка
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Objects "Справочник.Номенклатура,Документ.Заказ"
|
python ".opencode/skills/db-dump-xml/scripts/db-dump-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Objects "Справочник.Номенклатура,Документ.Заказ"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -ConfigDir "C:\WS\cfsrc" -Mode Full
|
python ".opencode/skills/db-dump-xml/scripts/db-dump-xml.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Dev" -UserName "Admin" -Password "secret" -ConfigDir "C:\WS\cfsrc" -Mode Full
|
||||||
|
|
||||||
# Выгрузка расширения
|
# Выгрузка расширения
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-dump-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
|
python ".opencode/skills/db-dump-xml/scripts/db-dump-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
|
||||||
```
|
```
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# db-dump-xml v1.6 — Dump 1C configuration to XML files
|
# db-dump-xml v1.8 — Dump 1C configuration to XML files
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Выгрузка конфигурации 1С в XML-файлы
|
Выгрузка конфигурации 1С в XML-файлы
|
||||||
@@ -128,7 +129,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,11 +138,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -197,8 +225,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Configuration exported successfully to: $ConfigDir" -ForegroundColor Green
|
Write-Host "Configuration exported successfully to: $ConfigDir" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-dump-xml v1.6 — Dump 1C configuration to XML files
|
# db-dump-xml v1.8 — Dump 1C configuration to XML files
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -149,7 +182,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"Configuration exported successfully to: {args.ConfigDir}")
|
print(f"Configuration exported successfully to: {args.ConfigDir}")
|
||||||
else:
|
else:
|
||||||
@@ -36,7 +36,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" <параметры>
|
python ".opencode/skills/db-load-cf/scripts/db-load-cf.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -63,11 +63,11 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" <п
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Файловая база
|
# Файловая база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "C:\backup\config.cf"
|
python ".opencode/skills/db-load-cf/scripts/db-load-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "C:\backup\config.cf"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test" -UserName "Admin" -Password "secret" -InputFile "config.cf"
|
python ".opencode/skills/db-load-cf/scripts/db-load-cf.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test" -UserName "Admin" -Password "secret" -InputFile "config.cf"
|
||||||
|
|
||||||
# Загрузка расширения
|
# Загрузка расширения
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-cf.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "ext.cfe" -Extension "МоёРасширение"
|
python ".opencode/skills/db-load-cf/scripts/db-load-cf.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "ext.cfe" -Extension "МоёРасширение"
|
||||||
```
|
```
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# db-load-cf v1.4 — Load 1C configuration from CF file
|
# db-load-cf v1.6 — Load 1C configuration from CF file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Загрузка конфигурации 1С из CF-файла
|
Загрузка конфигурации 1С из CF-файла
|
||||||
@@ -105,7 +106,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,11 +115,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -156,8 +184,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Configuration loaded successfully from: $InputFile" -ForegroundColor Green
|
Write-Host "Configuration loaded successfully from: $InputFile" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-load-cf v1.4 — Load 1C configuration from CF file
|
# db-load-cf v1.6 — Load 1C configuration from CF file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -118,7 +151,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"Configuration loaded successfully from: {args.InputFile}")
|
print(f"Configuration loaded successfully from: {args.InputFile}")
|
||||||
else:
|
else:
|
||||||
@@ -52,7 +52,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" <параметры>
|
python ".opencode/skills/db-load-dt/scripts/db-load-dt.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -80,10 +80,10 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" <п
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Файловая база
|
# Файловая база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "C:\backup\base.dt"
|
python ".opencode/skills/db-load-dt/scripts/db-load-dt.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -InputFile "C:\backup\base.dt"
|
||||||
|
|
||||||
# Серверная база с ускорением загрузки
|
# Серверная база с ускорением загрузки
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-dt.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test" -UserName "Admin" -Password "secret" -InputFile "base.dt" -JobsCount 4
|
python ".opencode/skills/db-load-dt/scripts/db-load-dt.py" -InfoBaseServer "srv01" -InfoBaseRef "MyApp_Test" -UserName "Admin" -Password "secret" -InputFile "base.dt" -JobsCount 4
|
||||||
```
|
```
|
||||||
|
|
||||||
## Связанные навыки
|
## Связанные навыки
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# db-load-dt v1.3 — Load 1C information base from DT file
|
# db-load-dt v1.5 — Load 1C information base from DT file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Загрузка информационной базы 1С из DT-файла
|
Загрузка информационной базы 1С из DT-файла
|
||||||
@@ -102,7 +103,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,11 +112,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -150,8 +178,9 @@ try {
|
|||||||
|
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Information base restored successfully from: $InputFile" -ForegroundColor Green
|
Write-Host "Information base restored successfully from: $InputFile" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-load-dt v1.3 — Load 1C information base from DT file
|
# db-load-dt v1.5 — Load 1C information base from DT file
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -115,7 +148,7 @@ def main():
|
|||||||
atexit.register(shutil.rmtree, ib_data, ignore_errors=True)
|
atexit.register(shutil.rmtree, ib_data, ignore_errors=True)
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"Information base restored successfully from: {args.InputFile}")
|
print(f"Information base restored successfully from: {args.InputFile}")
|
||||||
else:
|
else:
|
||||||
@@ -38,7 +38,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" <параметры>
|
python ".opencode/skills/db-load-git/scripts/db-load-git.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -70,8 +70,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" <
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Все незафиксированные изменения
|
# Все незафиксированные изменения
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source All -UpdateDB
|
python ".opencode/skills/db-load-git/scripts/db-load-git.py" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source All -UpdateDB
|
||||||
|
|
||||||
# Из диапазона коммитов
|
# Из диапазона коммитов
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-git.ps1" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source Commit -CommitRange "HEAD~3..HEAD"
|
python ".opencode/skills/db-load-git/scripts/db-load-git.py" -InfoBasePath "C:\Bases\MyDB" -ConfigDir "C:\WS\cfsrc" -Source Commit -CommitRange "HEAD~3..HEAD"
|
||||||
```
|
```
|
||||||
+53
-21
@@ -1,5 +1,6 @@
|
|||||||
# db-load-git v1.8 — Load Git changes into 1C database
|
# db-load-git v1.11 — Load Git changes into 1C database
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Загрузка изменений из Git в базу 1С
|
Загрузка изменений из Git в базу 1С
|
||||||
@@ -149,7 +150,7 @@ if (-not $DryRun) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +159,7 @@ if (-not $DryRun) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,6 +167,33 @@ if (-not $DryRun) {
|
|||||||
# --- Detect engine + validate connection (skip if DryRun) ---
|
# --- Detect engine + validate connection (skip if DryRun) ---
|
||||||
$engine = "1cv8"
|
$engine = "1cv8"
|
||||||
if (-not $DryRun) {
|
if (-not $DryRun) {
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
if ($engine -eq "ibcmd") {
|
if ($engine -eq "ibcmd") {
|
||||||
if (-not $InfoBasePath) {
|
if (-not $InfoBasePath) {
|
||||||
@@ -199,6 +227,15 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# --- Get changed files from Git ---
|
# --- Get changed files from Git ---
|
||||||
|
# Все git-вызовы для сбора путей идут через один хелпер с -c core.quotePath=false,
|
||||||
|
# иначе кириллические пути возвращаются в octal-виде и не распознаются (зеркало run_git в .py).
|
||||||
|
function Invoke-GitLines {
|
||||||
|
param([string[]]$GitArgs)
|
||||||
|
$out = git -c core.quotePath=false @GitArgs 2>&1
|
||||||
|
if ($LASTEXITCODE -eq 0) { return $out }
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
|
||||||
$changedFiles = @()
|
$changedFiles = @()
|
||||||
$ConfigDir = (Resolve-Path $ConfigDir).Path.TrimEnd('\')
|
$ConfigDir = (Resolve-Path $ConfigDir).Path.TrimEnd('\')
|
||||||
$configDirNormalized = $ConfigDir.Replace('\', '/')
|
$configDirNormalized = $ConfigDir.Replace('\', '/')
|
||||||
@@ -208,29 +245,22 @@ try {
|
|||||||
switch ($Source) {
|
switch ($Source) {
|
||||||
"Staged" {
|
"Staged" {
|
||||||
Write-Host "Getting staged changes..."
|
Write-Host "Getting staged changes..."
|
||||||
$raw = git diff --cached --name-only --relative 2>&1
|
$changedFiles += Invoke-GitLines -GitArgs @('diff', '--cached', '--name-only', '--relative')
|
||||||
if ($LASTEXITCODE -eq 0) { $changedFiles += $raw }
|
|
||||||
}
|
}
|
||||||
"Unstaged" {
|
"Unstaged" {
|
||||||
Write-Host "Getting unstaged changes..."
|
Write-Host "Getting unstaged changes..."
|
||||||
$raw = git diff --name-only --relative 2>&1
|
$changedFiles += Invoke-GitLines -GitArgs @('diff', '--name-only', '--relative')
|
||||||
if ($LASTEXITCODE -eq 0) { $changedFiles += $raw }
|
$changedFiles += Invoke-GitLines -GitArgs @('ls-files', '--others', '--exclude-standard')
|
||||||
$raw = git ls-files --others --exclude-standard 2>&1
|
|
||||||
if ($LASTEXITCODE -eq 0) { $changedFiles += $raw }
|
|
||||||
}
|
}
|
||||||
"Commit" {
|
"Commit" {
|
||||||
Write-Host "Getting changes from $CommitRange..."
|
Write-Host "Getting changes from $CommitRange..."
|
||||||
$raw = git diff --name-only --relative $CommitRange 2>&1
|
$changedFiles += Invoke-GitLines -GitArgs @('diff', '--name-only', '--relative', $CommitRange)
|
||||||
if ($LASTEXITCODE -eq 0) { $changedFiles += $raw }
|
|
||||||
}
|
}
|
||||||
"All" {
|
"All" {
|
||||||
Write-Host "Getting all uncommitted changes..."
|
Write-Host "Getting all uncommitted changes..."
|
||||||
$raw = git diff --cached --name-only --relative 2>&1
|
$changedFiles += Invoke-GitLines -GitArgs @('diff', '--cached', '--name-only', '--relative')
|
||||||
if ($LASTEXITCODE -eq 0) { $changedFiles += $raw }
|
$changedFiles += Invoke-GitLines -GitArgs @('diff', '--name-only', '--relative')
|
||||||
$raw = git diff --name-only --relative 2>&1
|
$changedFiles += Invoke-GitLines -GitArgs @('ls-files', '--others', '--exclude-standard')
|
||||||
if ($LASTEXITCODE -eq 0) { $changedFiles += $raw }
|
|
||||||
$raw = git ls-files --others --exclude-standard 2>&1
|
|
||||||
if ($LASTEXITCODE -eq 0) { $changedFiles += $raw }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -343,8 +373,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -ne 0) {
|
if ($exitCode -ne 0) {
|
||||||
Write-Host "Error loading changes (code: $exitCode)" -ForegroundColor Red
|
Write-Host "Error loading changes (code: $exitCode)" -ForegroundColor Red
|
||||||
if ($output) { Write-Host ($output | Out-String) }
|
if ($output) { Write-Host ($output | Out-String) }
|
||||||
@@ -358,8 +389,9 @@ try {
|
|||||||
if ($Password) { $applyArgs += "--password=$Password" }
|
if ($Password) { $applyArgs += "--password=$Password" }
|
||||||
$applyArgs += "--data=$tempDir"
|
$applyArgs += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($applyArgs -join ' ')"
|
Write-Host "Running: ibcmd $($applyArgs -join ' ')"
|
||||||
$applyOut = & $V8Path @applyArgs 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $applyArgs
|
||||||
$exitCode = $LASTEXITCODE
|
$applyOut = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Database configuration updated successfully" -ForegroundColor Green
|
Write-Host "Database configuration updated successfully" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+50
-17
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-load-git v1.8 — Load Git changes into 1C database
|
# db-load-git v1.11 — Load Git changes into 1C database
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def get_object_xml_from_subfile(relative_path):
|
def get_object_xml_from_subfile(relative_path):
|
||||||
"""Map sub-file path (BSL, HTML, etc.) to object XML path."""
|
"""Map sub-file path (BSL, HTML, etc.) to object XML path."""
|
||||||
parts = re.split(r"[\\/]", relative_path)
|
parts = re.split(r"[\\/]", relative_path)
|
||||||
@@ -77,7 +110,7 @@ def get_object_xml_from_subfile(relative_path):
|
|||||||
def run_git(config_dir, git_args):
|
def run_git(config_dir, git_args):
|
||||||
"""Run a git command in config_dir and return output lines on success."""
|
"""Run a git command in config_dir and return output lines on success."""
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["git"] + git_args,
|
["git", "-c", "core.quotePath=false"] + git_args,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
@@ -275,7 +308,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
print(f"Error loading changes (code: {result.returncode})", file=sys.stderr)
|
print(f"Error loading changes (code: {result.returncode})", file=sys.stderr)
|
||||||
if result.stdout:
|
if result.stdout:
|
||||||
@@ -295,7 +328,7 @@ def main():
|
|||||||
apply_args.append(f"--password={args.Password}")
|
apply_args.append(f"--password={args.Password}")
|
||||||
apply_args.append(f"--data={ib_data}")
|
apply_args.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(apply_args)}")
|
print(f"Running: ibcmd {' '.join(apply_args)}")
|
||||||
ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace")
|
ar = run_ibcmd([v8path] + apply_args, bool(args.UserName))
|
||||||
exit_code = ar.returncode
|
exit_code = ar.returncode
|
||||||
if exit_code == 0:
|
if exit_code == 0:
|
||||||
print("Database configuration updated successfully")
|
print("Database configuration updated successfully")
|
||||||
@@ -38,7 +38,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" <параметры>
|
python ".opencode/skills/db-load-xml/scripts/db-load-xml.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -88,14 +88,14 @@ Documents/Заказ/Forms/ФормаДокумента.xml
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Полная загрузка
|
# Полная загрузка
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
|
python ".opencode/skills/db-load-xml/scripts/db-load-xml.py" -V8Path "C:\Program Files\1cv8\8.3.25.1257\bin" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full
|
||||||
|
|
||||||
# Частичная загрузка конкретных файлов
|
# Частичная загрузка конкретных файлов
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Files "Catalogs/Номенклатура.xml,Catalogs/Номенклатура/Ext/ObjectModule.bsl"
|
python ".opencode/skills/db-load-xml/scripts/db-load-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Partial -Files "Catalogs/Номенклатура.xml,Catalogs/Номенклатура/Ext/ObjectModule.bsl"
|
||||||
|
|
||||||
# Загрузка расширения
|
# Загрузка расширения
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
|
python ".opencode/skills/db-load-xml/scripts/db-load-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\ext_src" -Mode Full -Extension "МоёРасширение"
|
||||||
|
|
||||||
# Загрузка + обновление БД в одном запуске
|
# Загрузка + обновление БД в одном запуске
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-load-xml.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full -UpdateDB
|
python ".opencode/skills/db-load-xml/scripts/db-load-xml.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -ConfigDir "C:\WS\cfsrc" -Mode Full -UpdateDB
|
||||||
```
|
```
|
||||||
+37
-7
@@ -1,5 +1,6 @@
|
|||||||
# db-load-xml v1.10 — Load 1C configuration from XML files
|
# db-load-xml v1.12 — Load 1C configuration from XML files
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Загрузка конфигурации 1С из XML-файлов
|
Загрузка конфигурации 1С из XML-файлов
|
||||||
@@ -137,7 +138,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,11 +147,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -217,8 +245,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -ne 0) {
|
if ($exitCode -ne 0) {
|
||||||
Write-Host "Error loading configuration from files (code: $exitCode)" -ForegroundColor Red
|
Write-Host "Error loading configuration from files (code: $exitCode)" -ForegroundColor Red
|
||||||
if ($output) { Write-Host ($output | Out-String) }
|
if ($output) { Write-Host ($output | Out-String) }
|
||||||
@@ -233,8 +262,9 @@ try {
|
|||||||
if ($Password) { $applyArgs += "--password=$Password" }
|
if ($Password) { $applyArgs += "--password=$Password" }
|
||||||
$applyArgs += "--data=$tempDir"
|
$applyArgs += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($applyArgs -join ' ')"
|
Write-Host "Running: ibcmd $($applyArgs -join ' ')"
|
||||||
$applyOut = & $V8Path @applyArgs 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $applyArgs
|
||||||
$exitCode = $LASTEXITCODE
|
$applyOut = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Database configuration updated successfully" -ForegroundColor Green
|
Write-Host "Database configuration updated successfully" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+49
-16
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-load-xml v1.10 — Load 1C configuration from XML files
|
# db-load-xml v1.12 — Load 1C configuration from XML files
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -167,7 +200,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
print(f"Error loading configuration from files (code: {result.returncode})", file=sys.stderr)
|
print(f"Error loading configuration from files (code: {result.returncode})", file=sys.stderr)
|
||||||
if result.stdout:
|
if result.stdout:
|
||||||
@@ -187,7 +220,7 @@ def main():
|
|||||||
apply_args.append(f"--password={args.Password}")
|
apply_args.append(f"--password={args.Password}")
|
||||||
apply_args.append(f"--data={ib_data}")
|
apply_args.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(apply_args)}")
|
print(f"Running: ibcmd {' '.join(apply_args)}")
|
||||||
ar = subprocess.run([v8path] + apply_args, capture_output=True, encoding="utf-8", errors="replace")
|
ar = run_ibcmd([v8path] + apply_args, bool(args.UserName))
|
||||||
exit_code = ar.returncode
|
exit_code = ar.returncode
|
||||||
if exit_code == 0:
|
if exit_code == 0:
|
||||||
print("Database configuration updated successfully")
|
print("Database configuration updated successfully")
|
||||||
@@ -36,7 +36,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" <параметры>
|
python ".opencode/skills/db-run/scripts/db-run.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -63,14 +63,14 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" <пар
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Простой запуск
|
# Простой запуск
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
|
python ".opencode/skills/db-run/scripts/db-run.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
|
||||||
|
|
||||||
# Запуск с обработкой
|
# Запуск с обработкой
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Execute "C:\epf\МояОбработка.epf"
|
python ".opencode/skills/db-run/scripts/db-run.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Execute "C:\epf\МояОбработка.epf"
|
||||||
|
|
||||||
# Открыть по навигационной ссылке
|
# Открыть по навигационной ссылке
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -URL "e1cib/data/Справочник.Номенклатура"
|
python ".opencode/skills/db-run/scripts/db-run.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -URL "e1cib/data/Справочник.Номенклатура"
|
||||||
|
|
||||||
# Серверная база с параметром запуска
|
# Серверная база с параметром запуска
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-run.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -CParam "ЗапуститьОбновление"
|
python ".opencode/skills/db-run/scripts/db-run.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -CParam "ЗапуститьОбновление"
|
||||||
```
|
```
|
||||||
+4
-3
@@ -1,5 +1,6 @@
|
|||||||
# db-run v1.1 — Launch 1C:Enterprise
|
# db-run v1.2 — Launch 1C:Enterprise
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Запуск 1С:Предприятие
|
Запуск 1С:Предприятие
|
||||||
@@ -108,7 +109,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +118,7 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
+26
-14
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-run v1.1 — Launch 1C:Enterprise
|
# db-run v1.2 — Launch 1C:Enterprise
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -32,32 +32,44 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" <параметры>
|
python ".opencode/skills/db-update/scripts/db-update.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -76,11 +76,11 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" <п
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Обычное обновление (файловая база)
|
# Обычное обновление (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
|
python ".opencode/skills/db-update/scripts/db-update.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin"
|
||||||
|
|
||||||
# Динамическое обновление (серверная база)
|
# Динамическое обновление (серверная база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -Dynamic "+"
|
python ".opencode/skills/db-update/scripts/db-update.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -Dynamic "+"
|
||||||
|
|
||||||
# Обновление расширения
|
# Обновление расширения
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/db-update.ps1" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Extension "МоёРасширение"
|
python ".opencode/skills/db-update/scripts/db-update.py" -InfoBasePath "C:\Bases\MyDB" -UserName "Admin" -Extension "МоёРасширение"
|
||||||
```
|
```
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# db-update v1.4 — Update 1C database configuration
|
# db-update v1.6 — Update 1C database configuration
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Обновление конфигурации базы данных 1С
|
Обновление конфигурации базы данных 1С
|
||||||
@@ -118,7 +119,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,11 +128,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
|
|
||||||
# --- Validate connection ---
|
# --- Validate connection ---
|
||||||
@@ -164,8 +192,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "Database configuration updated successfully" -ForegroundColor Green
|
Write-Host "Database configuration updated successfully" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# db-update v1.4 — Update 1C database configuration
|
# db-update v1.6 — Update 1C database configuration
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -119,7 +152,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, bool(args.UserName))
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print("Database configuration updated successfully")
|
print("Database configuration updated successfully")
|
||||||
else:
|
else:
|
||||||
@@ -40,7 +40,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <параметры>
|
python ".opencode/skills/epf-build/scripts/epf-build.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -62,8 +62,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" <п
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Сборка обработки (файловая база)
|
# Сборка обработки (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
|
python ".opencode/skills/epf-build/scripts/epf-build.py" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-build.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
|
python ".opencode/skills/epf-build/scripts/epf-build.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МояОбработка.xml" -OutputFile "build/МояОбработка.epf"
|
||||||
```
|
```
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# epf-build v1.4 — Build external data processor or report (EPF/ERF) from XML sources
|
# epf-build v1.6 — Build external data processor or report (EPF/ERF) from XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Сборка внешней обработки/отчёта 1С из XML-исходников
|
Сборка внешней обработки/отчёта 1С из XML-исходников
|
||||||
@@ -99,7 +100,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,11 +109,38 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
if ($engine -eq "ibcmd" -and $InfoBaseServer -and $InfoBaseRef) {
|
if ($engine -eq "ibcmd" -and $InfoBaseServer -and $InfoBaseRef) {
|
||||||
Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath or omit for stub)" -ForegroundColor Red
|
Write-Host "Error: ibcmd supports file infobases only (use -InfoBasePath or omit for stub)" -ForegroundColor Red
|
||||||
@@ -161,8 +189,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "External data processor/report built successfully: $OutputFile" -ForegroundColor Green
|
Write-Host "External data processor/report built successfully: $OutputFile" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# epf-build v1.4 — Build external data processor or report (EPF/ERF) from XML sources
|
# epf-build v1.6 — Build external data processor or report (EPF/ERF) from XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -134,7 +167,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, warn_no_user=False)
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"External data processor/report built successfully: {args.OutputFile}")
|
print(f"External data processor/report built successfully: {args.OutputFile}")
|
||||||
else:
|
else:
|
||||||
+31
-3
@@ -1,4 +1,4 @@
|
|||||||
# stub-db-create v1.2 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
# stub-db-create v1.3 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -1253,6 +1253,33 @@ $propsXml </Properties>$childObjLine
|
|||||||
}
|
}
|
||||||
|
|
||||||
# --- 5a. Stub via ibcmd (one call: create [--import --apply]) ---
|
# --- 5a. Stub via ibcmd (one call: create [--import --apply]) ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$stubEngine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$stubEngine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
if ($stubEngine -eq "ibcmd") {
|
if ($stubEngine -eq "ibcmd") {
|
||||||
Write-Host "Creating infobase (ibcmd): $TempBasePath"
|
Write-Host "Creating infobase (ibcmd): $TempBasePath"
|
||||||
@@ -1261,8 +1288,9 @@ if ($stubEngine -eq "ibcmd") {
|
|||||||
$ibArgs = @("infobase", "create", "--db-path=$TempBasePath", "--create-database")
|
$ibArgs = @("infobase", "create", "--db-path=$TempBasePath", "--create-database")
|
||||||
if ($hasRefTypes) { $ibArgs += "--import=$(Join-Path $TempBasePath 'cfg')", "--apply", "--force" }
|
if ($hasRefTypes) { $ibArgs += "--import=$(Join-Path $TempBasePath 'cfg')", "--apply", "--force" }
|
||||||
$ibArgs += "--data=$ibData"
|
$ibArgs += "--data=$ibData"
|
||||||
$ibOut = & $V8Path @ibArgs 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $ibArgs
|
||||||
$ibRc = $LASTEXITCODE
|
$ibOut = $__ib.Output
|
||||||
|
$ibRc = $__ib.ExitCode
|
||||||
Remove-Item -Path $ibData -Recurse -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path $ibData -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
if ($ibRc -ne 0) {
|
if ($ibRc -ne 0) {
|
||||||
if ($ibOut) { Write-Host ($ibOut | Out-String) }
|
if ($ibOut) { Write-Host ($ibOut | Out-String) }
|
||||||
+23
-2
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# stub-db-create v1.2 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
# stub-db-create v1.3 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -12,6 +12,27 @@ import tempfile
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def new_uuid():
|
def new_uuid():
|
||||||
return str(uuid.uuid4())
|
return str(uuid.uuid4())
|
||||||
|
|
||||||
@@ -1044,7 +1065,7 @@ def main():
|
|||||||
if has_ref_types:
|
if has_ref_types:
|
||||||
ib_args += [f'--import={os.path.join(temp_base, "cfg")}', '--apply', '--force']
|
ib_args += [f'--import={os.path.join(temp_base, "cfg")}', '--apply', '--force']
|
||||||
ib_args.append(f'--data={ib_data}')
|
ib_args.append(f'--data={ib_data}')
|
||||||
result = subprocess.run(ib_args, capture_output=True, encoding='utf-8', errors='replace')
|
result = run_ibcmd(ib_args, warn_no_user=False)
|
||||||
shutil.rmtree(ib_data, ignore_errors=True)
|
shutil.rmtree(ib_data, ignore_errors=True)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
if result.stdout:
|
if result.stdout:
|
||||||
@@ -39,7 +39,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" <параметры>
|
python ".opencode/skills/epf-dump/scripts/epf-dump.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -62,8 +62,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" <па
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Разборка обработки (файловая база)
|
# Разборка обработки (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МояОбработка.epf" -OutputDir "src"
|
python ".opencode/skills/epf-dump/scripts/epf-dump.py" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МояОбработка.epf" -OutputDir "src"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-dump.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МояОбработка.epf" -OutputDir "src"
|
python ".opencode/skills/epf-dump/scripts/epf-dump.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МояОбработка.epf" -OutputDir "src"
|
||||||
```
|
```
|
||||||
+34
-5
@@ -1,5 +1,6 @@
|
|||||||
# epf-dump v1.4 — Dump external data processor or report (EPF/ERF) to XML sources
|
# epf-dump v1.6 — Dump external data processor or report (EPF/ERF) to XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
# NB: *nix-раскладку платформы (/opt/1cv8/<ver>/1cv8, без .exe) знает только .py-порт — PS на *nix не исполняется.
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Разборка внешней обработки/отчёта 1С в XML-исходники
|
Разборка внешней обработки/отчёта 1С в XML-исходники
|
||||||
@@ -106,7 +107,7 @@ if (-not $V8Path) {
|
|||||||
$V8Path = $found.FullName
|
$V8Path = $found.FullName
|
||||||
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
Write-Host "Auto-selected platform $($found.Directory.Parent.Name): $V8Path" -ForegroundColor Yellow
|
||||||
} else {
|
} else {
|
||||||
Write-Host "Error: 1cv8.exe not found. Specify -V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found. Specify -V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +116,7 @@ if (Test-Path $V8Path -PathType Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (-not (Test-Path $V8Path)) {
|
if (-not (Test-Path $V8Path)) {
|
||||||
Write-Host "Error: 1cv8.exe not found at $V8Path" -ForegroundColor Red
|
Write-Host "Error: 1C executable not found at $V8Path" -ForegroundColor Red
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +128,33 @@ if (-not $InfoBasePath -and (-not $InfoBaseServer -or -not $InfoBaseRef)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
# --- Detect engine (ibcmd vs 1cv8) by exe name ---
|
||||||
|
function Invoke-IbcmdProcess {
|
||||||
|
# Run ibcmd non-interactively: a closed stdin pipe (EOF) makes ibcmd's auth prompt
|
||||||
|
# fast-fail instead of hanging. Returns @{ Output; ExitCode }. cp866 decodes ibcmd's
|
||||||
|
# native OEM output. The 1cv8/DESIGNER branch keeps using Start-Process.
|
||||||
|
param([string]$Exe, [string[]]$IbArgs)
|
||||||
|
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||||
|
$psi.FileName = $Exe
|
||||||
|
$psi.Arguments = ($IbArgs | ForEach-Object { if ($_ -match '[\s"]') { '"' + ($_ -replace '"', '\"') + '"' } else { $_ } }) -join ' '
|
||||||
|
$psi.UseShellExecute = $false
|
||||||
|
$psi.CreateNoWindow = $true
|
||||||
|
$psi.RedirectStandardInput = $true
|
||||||
|
$psi.RedirectStandardOutput = $true
|
||||||
|
$psi.RedirectStandardError = $true
|
||||||
|
try {
|
||||||
|
$psi.StandardOutputEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
$psi.StandardErrorEncoding = [System.Text.Encoding]::GetEncoding(866)
|
||||||
|
} catch {}
|
||||||
|
$p = [System.Diagnostics.Process]::Start($psi)
|
||||||
|
$p.StandardInput.Close()
|
||||||
|
$out = $p.StandardOutput.ReadToEnd()
|
||||||
|
$err = $p.StandardError.ReadToEnd()
|
||||||
|
$p.WaitForExit()
|
||||||
|
if ($err) { $out += $err }
|
||||||
|
return [pscustomobject]@{ Output = $out; ExitCode = $p.ExitCode }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
$engine = if ((Split-Path $V8Path -Leaf) -match '^ibcmd') { "ibcmd" } else { "1cv8" }
|
||||||
if ($engine -eq "ibcmd") {
|
if ($engine -eq "ibcmd") {
|
||||||
if (-not $InfoBasePath) {
|
if (-not $InfoBasePath) {
|
||||||
@@ -162,8 +190,9 @@ try {
|
|||||||
if ($Password) { $arguments += "--password=$Password" }
|
if ($Password) { $arguments += "--password=$Password" }
|
||||||
$arguments += "--data=$tempDir"
|
$arguments += "--data=$tempDir"
|
||||||
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
Write-Host "Running: ibcmd $($arguments -join ' ')"
|
||||||
$output = & $V8Path @arguments 2>&1
|
$__ib = Invoke-IbcmdProcess $V8Path $arguments
|
||||||
$exitCode = $LASTEXITCODE
|
$output = $__ib.Output
|
||||||
|
$exitCode = $__ib.ExitCode
|
||||||
if ($exitCode -eq 0) {
|
if ($exitCode -eq 0) {
|
||||||
Write-Host "External data processor/report dumped successfully to: $OutputDir" -ForegroundColor Green
|
Write-Host "External data processor/report dumped successfully to: $OutputDir" -ForegroundColor Green
|
||||||
} else {
|
} else {
|
||||||
+48
-15
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# epf-dump v1.4 — Dump external data processor or report (EPF/ERF) to XML sources
|
# epf-dump v1.6 — Dump external data processor or report (EPF/ERF) to XML sources
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -36,36 +36,69 @@ def _find_project_v8path():
|
|||||||
d = parent
|
d = parent
|
||||||
|
|
||||||
|
|
||||||
|
def _version_dir(p):
|
||||||
|
"""Version dir for both Windows (.../1cv8/<ver>/bin/1cv8.exe) and *nix (.../1cv8/<ver>/1cv8)."""
|
||||||
|
parent = os.path.dirname(p)
|
||||||
|
if os.path.basename(parent).lower() == "bin":
|
||||||
|
parent = os.path.dirname(parent)
|
||||||
|
return os.path.basename(parent)
|
||||||
|
|
||||||
|
|
||||||
def _version_key(p):
|
def _version_key(p):
|
||||||
"""Numeric sort key from version dir name (.../1cv8/<ver>/bin/1cv8.exe)."""
|
"""Numeric sort key from version dir name."""
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(p)))
|
return [int(x) for x in re.findall(r"\d+", _version_dir(p))]
|
||||||
return [int(x) for x in re.findall(r"\d+", ver)]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_v8path(v8path):
|
def resolve_v8path(v8path):
|
||||||
"""Resolve path to 1cv8.exe."""
|
"""Resolve path to a 1C executable (1cv8; ibcmd only when given explicitly)."""
|
||||||
if not v8path:
|
if not v8path:
|
||||||
v8path = _find_project_v8path()
|
v8path = _find_project_v8path()
|
||||||
if not v8path:
|
if not v8path:
|
||||||
candidates = (
|
if os.name == "nt":
|
||||||
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
candidates = (
|
||||||
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
glob.glob(r"C:\Program Files\1cv8\*\bin\1cv8.exe")
|
||||||
)
|
+ glob.glob(r"C:\Program Files (x86)\1cv8\*\bin\1cv8.exe")
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# PY-only: PS-порт на *nix не исполняется, поэтому *nix-раскладки нет в .ps1.
|
||||||
|
candidates = glob.glob("/opt/1cv8/*/1cv8")
|
||||||
if candidates:
|
if candidates:
|
||||||
v8path = max(candidates, key=_version_key)
|
v8path = max(candidates, key=_version_key)
|
||||||
ver = os.path.basename(os.path.dirname(os.path.dirname(v8path)))
|
print(f"Auto-selected platform {_version_dir(v8path)}: {v8path}")
|
||||||
print(f"Auto-selected platform {ver}: {v8path}")
|
|
||||||
else:
|
else:
|
||||||
print("Error: 1cv8.exe not found. Specify -V8Path", file=sys.stderr)
|
print("Error: 1C executable not found. Specify -V8Path", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if os.path.isdir(v8path):
|
if os.path.isdir(v8path):
|
||||||
v8path = os.path.join(v8path, "1cv8.exe")
|
# PY-only: на *nix исполняемый называется "1cv8" (без .exe); ibcmd — только явным путём.
|
||||||
|
exe = "1cv8.exe" if os.name == "nt" else "1cv8"
|
||||||
|
v8path = os.path.join(v8path, exe)
|
||||||
if not os.path.isfile(v8path):
|
if not os.path.isfile(v8path):
|
||||||
print(f"Error: 1cv8.exe not found at {v8path}", file=sys.stderr)
|
print(f"Error: 1C executable not found at {v8path}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return v8path
|
return v8path
|
||||||
|
|
||||||
|
|
||||||
|
IBCMD_NOUSER_HINT = (
|
||||||
|
"[ibcmd] No -UserName/-Password given; the infobase may require authentication. "
|
||||||
|
"On Windows ibcmd reads credentials from the console (stdin is ignored), so this "
|
||||||
|
"call may block instead of failing. If it does not return promptly, abort and "
|
||||||
|
"re-run with -UserName and -Password.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_ibcmd(cmd, has_username=False, warn_no_user=True):
|
||||||
|
"""Run an ibcmd command non-interactively.
|
||||||
|
|
||||||
|
input="" closes stdin (EOF) so ibcmd's auth prompt fast-fails instead of hanging.
|
||||||
|
On Windows without -UserName ibcmd reads the console directly and may still block —
|
||||||
|
that residual case is flagged via IBCMD_NOUSER_HINT (model-facing).
|
||||||
|
"""
|
||||||
|
if warn_no_user and os.name == "nt" and not has_username:
|
||||||
|
sys.stderr.write(IBCMD_NOUSER_HINT)
|
||||||
|
sys.stderr.flush()
|
||||||
|
return subprocess.run(cmd, input="", capture_output=True, encoding="utf-8", errors="replace")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
sys.stderr.reconfigure(encoding="utf-8")
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
@@ -131,7 +164,7 @@ def main():
|
|||||||
arguments.append(f"--password={args.Password}")
|
arguments.append(f"--password={args.Password}")
|
||||||
arguments.append(f"--data={ib_data}")
|
arguments.append(f"--data={ib_data}")
|
||||||
print(f"Running: ibcmd {' '.join(arguments)}")
|
print(f"Running: ibcmd {' '.join(arguments)}")
|
||||||
result = subprocess.run([v8path] + arguments, capture_output=True, encoding="utf-8", errors="replace")
|
result = run_ibcmd([v8path] + arguments, warn_no_user=False)
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"External data processor/report dumped successfully to: {args.OutputDir}")
|
print(f"External data processor/report dumped successfully to: {args.OutputDir}")
|
||||||
else:
|
else:
|
||||||
@@ -30,7 +30,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/init.ps1" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"]
|
python ".opencode/skills/epf-init/scripts/init.py" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Дальнейшие шаги
|
## Дальнейшие шаги
|
||||||
@@ -24,7 +24,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-validate.ps1" -ObjectPath "src/МояОбработка"
|
python ".opencode/skills/epf-validate/scripts/epf-validate.py" -ObjectPath "src/МояОбработка"
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/epf-validate.ps1" -ObjectPath "src/МояОбработка/МояОбработка.xml"
|
python ".opencode/skills/epf-validate/scripts/epf-validate.py" -ObjectPath "src/МояОбработка/МояОбработка.xml"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ allowed-tools:
|
|||||||
Используй общий скрипт из epf-build:
|
Используй общий скрипт из epf-build:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.ps1" <параметры>
|
python ".opencode/skills/epf-build/scripts/epf-build.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -64,8 +64,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-bu
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Сборка отчёта (файловая база)
|
# Сборка отчёта (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.ps1" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
|
python ".opencode/skills/epf-build/scripts/epf-build.py" -InfoBasePath "C:\Bases\MyDB" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-build/scripts/epf-build.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
|
python ".opencode/skills/epf-build/scripts/epf-build.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -SourceFile "src/МойОтчёт.xml" -OutputFile "build/МойОтчёт.erf"
|
||||||
```
|
```
|
||||||
@@ -41,7 +41,7 @@ allowed-tools:
|
|||||||
Используй общий скрипт из epf-dump:
|
Используй общий скрипт из epf-dump:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.ps1" <параметры>
|
python ".opencode/skills/epf-dump/scripts/epf-dump.py" <параметры>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Параметры скрипта
|
### Параметры скрипта
|
||||||
@@ -64,8 +64,8 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dum
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Разборка отчёта (файловая база)
|
# Разборка отчёта (файловая база)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.ps1" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
|
python ".opencode/skills/epf-dump/scripts/epf-dump.py" -InfoBasePath "C:\Bases\MyDB" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
|
||||||
|
|
||||||
# Серверная база
|
# Серверная база
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-dump/scripts/epf-dump.ps1" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
|
python ".opencode/skills/epf-dump/scripts/epf-dump.py" -InfoBaseServer "srv01" -InfoBaseRef "MyDB" -UserName "Admin" -Password "secret" -InputFile "build/МойОтчёт.erf" -OutputDir "src"
|
||||||
```
|
```
|
||||||
@@ -31,7 +31,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/init.ps1" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"] [-WithSKD]
|
python ".opencode/skills/erf-init/scripts/init.py" -Name "<Name>" [-Synonym "<Synonym>"] [-SrcDir "<SrcDir>"] [-WithSKD]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Дальнейшие шаги
|
## Дальнейшие шаги
|
||||||
@@ -26,7 +26,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-validate/scripts/epf-validate.ps1" -ObjectPath "src/МойОтчёт"
|
python ".opencode/skills/epf-validate/scripts/epf-validate.py" -ObjectPath "src/МойОтчёт"
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/../epf-validate/scripts/epf-validate.ps1" -ObjectPath "src/МойОтчёт/МойОтчёт.xml"
|
python ".opencode/skills/epf-validate/scripts/epf-validate.py" -ObjectPath "src/МойОтчёт/МойОтчёт.xml"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ allowed-tools:
|
|||||||
## Команда
|
## Команда
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-add.ps1" -ObjectPath "<ObjectPath>" -FormName "<FormName>" [-Purpose "<Purpose>"] [-Synonym "<Synonym>"] [-SetDefault]
|
python ".opencode/skills/form-add/scripts/form-add.py" -ObjectPath "<ObjectPath>" -FormName "<FormName>" [-Purpose "<Purpose>"] [-Synonym "<Synonym>"] [-SetDefault]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Purpose — назначение формы
|
## Purpose — назначение формы
|
||||||
@@ -29,10 +29,10 @@ allowed-tools:
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Режим JSON DSL
|
# Режим JSON DSL
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-compile.ps1" -JsonPath "<json>" -OutputPath "<Form.xml>"
|
python ".opencode/skills/form-compile/scripts/form-compile.py" -JsonPath "<json>" -OutputPath "<Form.xml>"
|
||||||
|
|
||||||
# Режим from-object (объект и purpose выводятся из OutputPath; Document и Catalog)
|
# Режим from-object (объект и purpose выводятся из OutputPath; Document и Catalog)
|
||||||
powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/form-compile.ps1" -FromObject -OutputPath "<.../TypePlural/ObjectName/Forms/FormName/Ext/Form.xml>"
|
python ".opencode/skills/form-compile/scripts/form-compile.py" -FromObject -OutputPath "<.../TypePlural/ObjectName/Forms/FormName/Ext/Form.xml>"
|
||||||
```
|
```
|
||||||
|
|
||||||
## JSON DSL — справка
|
## JSON DSL — справка
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user