Compare commits
84 Commits
92f3dd696f
...
ad2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aed04e8ca4 | ||
|
|
88dc431cfa | ||
|
|
7431bfd52b | ||
|
|
505bc12355 | ||
| 0dbc2f98e0 | |||
|
|
3b3075503f | ||
|
|
77c23635df | ||
|
|
a3d7c01bbb | ||
|
|
c8a4107a51 | ||
|
|
8470e98a8a | ||
|
|
93934b625b | ||
|
|
e426dd8b16 | ||
|
|
b83d34ba50 | ||
|
|
ece3222d3a | ||
|
|
d7d9f72fc6 | ||
| 9011670fce | |||
| 9288f3ba93 | |||
| 5a73b18409 | |||
|
|
823bd935fd | ||
|
|
3dedd0c864 | ||
|
|
c51cdbdabc | ||
| 0ca5b2b73d | |||
| d95251d880 | |||
| 5ca81f8296 | |||
| 80509523c8 | |||
| ad88fc31f0 | |||
| a3a47f2d5e | |||
| 89a862c993 | |||
| 5362dc780a | |||
| cef97725b8 | |||
| 122b87a1d6 | |||
| 395333c85c | |||
| 6d60bf5295 | |||
| bdd070f055 | |||
| a29d00c6b2 | |||
| 37aaa6660b | |||
| 6cc9043b8e | |||
| 826141a319 | |||
| 87f5a9306a | |||
| a1e0442d8b | |||
| a8c8c6b7b6 | |||
| 8a0611d4d1 | |||
| cf2b229be5 | |||
| a706f6a94b | |||
| 604c9d9d4b | |||
| 5cbd49ce24 | |||
| 98ea867d2c | |||
| 481b02ed46 | |||
| fc0d12d3cf | |||
| 7c088e57d8 | |||
| 7c8488ad14 | |||
| c296bb9ea0 | |||
| c3eb709dd5 | |||
| 1b17c8144a | |||
| 68e26379aa | |||
| 649565a868 | |||
| 31e70bc18a | |||
| acea558406 | |||
| 4e84a7f810 | |||
| a2b8332770 | |||
| ee89727662 | |||
| 1adc2ed3a4 | |||
| 2b4ca5a8c6 | |||
| b0af0c5828 | |||
| 0262802047 | |||
| 2e75ee3a52 | |||
| c597213ed3 | |||
| bd74b2a05e | |||
| 1b9973e150 | |||
| 6e892bb674 | |||
| 99e83a2848 | |||
| d320958fa8 | |||
| 068888202c | |||
| 6c2c693e6d | |||
| 78528d545e | |||
| 000ee3da5c | |||
| 470638ff86 | |||
| 1a26eb051a | |||
| c79c81e842 | |||
| c629890e32 | |||
| fa15b03180 | |||
| a1a19f8c00 | |||
| f81872784b | |||
| b2874b4728 |
246
.claude/CLAUDE.md
Normal file
246
.claude/CLAUDE.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# ClaudeTools on AD2 (Dataforth Domain Controller)
|
||||
|
||||
## Identity
|
||||
|
||||
This is the AD2 workstation instance of ClaudeTools. This machine is a Windows Server on the Dataforth LAN (192.168.0.6). Your scope is Dataforth-only -- you do not need context about other clients.
|
||||
|
||||
## NO EMOJIS
|
||||
|
||||
Use ASCII markers: [OK], [ERROR], [WARNING], [SUCCESS], [INFO]
|
||||
|
||||
---
|
||||
|
||||
## Git & Sync
|
||||
|
||||
### Gitea Credentials (no 1Password on this machine)
|
||||
- URL: https://git.azcomputerguru.com
|
||||
- Username: mike@azcomputerguru.com
|
||||
- Password: Gptf*77ttb123!@#-git
|
||||
- URL-encoded password: Gptf%2A77ttb123%21%40%23-git
|
||||
- API Token: 9b1da4b79a38ef782268341d25a4b6880572063f
|
||||
- Remote: https://mike%40azcomputerguru.com:Gptf%2A77ttb123%21%40%23-git@git.azcomputerguru.com/azcomputerguru/claudetools.git
|
||||
|
||||
### Branch: ad2
|
||||
This machine operates on the `ad2` branch. The main workstation merges into main.
|
||||
|
||||
### /save behavior
|
||||
Save session logs to `session-logs/YYYY-MM-DD-session-ad2.md` (note the -ad2 suffix).
|
||||
After saving, commit and push to origin/ad2.
|
||||
|
||||
### /sync behavior
|
||||
```
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
git push origin ad2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dataforth Network
|
||||
|
||||
| Host | IP | Role | Notes |
|
||||
|------|-----|------|-------|
|
||||
| AD1 | 192.168.0.27 | Primary DC | Disk at 90%, C:\Engineering = 787 GB |
|
||||
| **AD2** | **192.168.0.6** | **This machine** | Secondary DC, TestDataDB, file shares |
|
||||
| D2TESTNAS | 192.168.0.9 | SMB1 proxy for DOS | Debian 13, Samba, SSH root/Paper123!@#-nas |
|
||||
| UDM | 192.168.0.254 | Gateway/Router | UniFi Dream Machine |
|
||||
| ESXi-122 | 192.168.0.122 | Hypervisor | ESXi |
|
||||
| ESXi-124 | 192.168.0.124 | Hypervisor | ESXi |
|
||||
| DOS stations | TS-01 to TS-30+ | Test stations | DOS 6.22, QuickBASIC ATE software |
|
||||
|
||||
### Credentials
|
||||
- AD Sysadmin: INTRANET\sysadmin / Paper123!@#
|
||||
- D2TESTNAS SSH: root@192.168.0.9 / Paper123!@#-nas
|
||||
- D2TESTNAS Samba: guest access (no password)
|
||||
- WINS/NPS: 192.168.0.27:1812/1813
|
||||
- M365 Tenant: 7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584
|
||||
- Rsync daemon (NAS): port 873, module "test", user rsync / IQ203s32119
|
||||
|
||||
---
|
||||
|
||||
## Local Resources
|
||||
|
||||
| Resource | Path |
|
||||
|----------|------|
|
||||
| TestDataDB app | C:\Shares\testdatadb\ |
|
||||
| Test database | C:\Shares\testdatadb\database\testdata.db (SQLite, 2.2M+ records) |
|
||||
| TestDataDB API | http://localhost:3000 |
|
||||
| Parsers | C:\Shares\testdatadb\parsers\ (multiline.js, csvline.js, shtfile.js, spec-reader.js) |
|
||||
| Templates | C:\Shares\testdatadb\templates\datasheet-exact.js |
|
||||
| Import script | C:\Shares\testdatadb\database\import.js |
|
||||
| Export script | C:\Shares\testdatadb\database\export-datasheets.js |
|
||||
| Stage import | C:\Shares\testdatadb\import-all-stage.js |
|
||||
| NAS share | \\D2TESTNAS\test (mapped as T:) |
|
||||
| Datasheets share | X:\For_Web |
|
||||
| ProdSW (BAT files) | C:\Shares\test\COMMON\ProdSW\ |
|
||||
| Sync script | C:\Shares\test\scripts\Sync-FromNAS.ps1 (bidirectional, 15-min schedule) |
|
||||
|
||||
---
|
||||
|
||||
## DOS Update System - Batch Files
|
||||
|
||||
### Boot Sequence on DOS Machines
|
||||
```
|
||||
AUTOEXEC.BAT (v4.1)
|
||||
-> STARTNET.BAT (v2.0) -- init network, map T: and X: drives
|
||||
-> ATESYNC.BAT
|
||||
-> CTONW.BAT (v5.0) -- upload test data to network
|
||||
-> CTONWTXT.BAT (v2.3) -- upload C:\STAGE\*.TXT to T:\STAGE\%MACHINE%
|
||||
-> NWTOC.BAT (v5.0) -- download updates from network
|
||||
```
|
||||
|
||||
### Current Production Versions (on AD2 & NAS)
|
||||
| File | Version | Last Update | Purpose |
|
||||
|------|---------|-------------|---------|
|
||||
| AUTOEXEC.BAT | v4.1 | 2026-03-12 | Startup config |
|
||||
| STARTNET.BAT | v2.0 | 2026-01-20 | Network init |
|
||||
| NWTOC.BAT | v5.0 | 2026-03-16 | Download updates from network |
|
||||
| CTONW.BAT | v5.0 | 2026-03-28 | Upload test data (5 steps with echo) |
|
||||
| CTONWTXT.BAT | v2.3 | 2026-03-28 | Upload Stage TXT files (no MD, dirs pre-created) |
|
||||
| CHECKUPD.BAT | v1.3 | 2026-01-20 | Check for updates |
|
||||
| UPDATE.BAT | v2.3 | 2026-01-20 | Full system backup |
|
||||
| STAGE.BAT | v1.0 | Original | Stage system file updates |
|
||||
| DEPLOY.BAT | v1.0 | 2026-01-20 | One-time deployment installer |
|
||||
|
||||
### DOS 6.22 Compatibility Rules
|
||||
- NO `IF NOT` -- unreliable on DOS 6.22. Use positive `IF EXIST` with GOTO
|
||||
- NO `IF /I` (case-insensitive compare)
|
||||
- NO `FOR /F` loops
|
||||
- NO `%COMPUTERNAME%` -- use `%MACHINE%` (set during DEPLOY)
|
||||
- `XCOPY /D` requires date parameter (`/D:mm-dd-yy`)
|
||||
- `MD` fails with error on existing directories -- pre-create dirs server-side
|
||||
- `COPY` without `/Y` hangs on overwrite prompts
|
||||
- All paths UPPERCASE for Samba compatibility
|
||||
- Line endings MUST be CRLF (0D 0A)
|
||||
|
||||
---
|
||||
|
||||
## Serial Number Encoding (DOS 8.3 filenames)
|
||||
|
||||
QuickBASIC ATE encodes long serial numbers for 8.3 filenames:
|
||||
```
|
||||
First 2 digits replaced with hex letter if serial too long:
|
||||
178236-12 -> H8236-12.TXT (17 -> H, charCode 72 - 55 = 17)
|
||||
10819-1 -> A819-1.TXT (10 -> A, charCode 65 - 55 = 10)
|
||||
|
||||
Decode: letter.charCodeAt(0) - 55 = numeric prefix
|
||||
Only applies when filename starts with [A-Z] followed by digits.
|
||||
|
||||
H-prefix files have decoded SN inside the file (SN: 178236-12)
|
||||
A-prefix files have encoded SN inside the file (SN: A819-1) -- must decode to 10819-1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Datasheet Pipeline
|
||||
|
||||
### 5-Stage Architecture
|
||||
1. **DOS Test Programs** -> Write DAT files to C:\ATE\*LOG\ and TXT to C:\STAGE\
|
||||
2. **Boot Upload** -> CTONW.BAT copies DAT to T:\%MACHINE%\LOGS\, CTONWTXT copies TXT to T:\STAGE\%MACHINE%
|
||||
3. **NAS <-> AD2 Sync** -> Rsync every 15 min (Sync-FromNAS.ps1 scheduled task)
|
||||
4. **TestDataDB Import** -> import.js parses DAT into SQLite; export-datasheets.js generates TXT to X:\For_Web
|
||||
5. **Web Share** -> X:\For_Web\ holds validated datasheets (501K+ files)
|
||||
|
||||
### import-all-stage.js (ready to run)
|
||||
Located at `C:\Shares\testdatadb\import-all-stage.js`. Processes ~8,100 TXT files:
|
||||
- Scans \\D2TESTNAS\test\STAGE\TS-*\*.TXT
|
||||
- Decodes hex-prefix serial numbers
|
||||
- Cross-references testdata.db by (serial_number, model_number)
|
||||
- Inserts missing records as log_type='SHT'
|
||||
- Copies to X:\For_Web\{decoded_serial}.TXT
|
||||
|
||||
```
|
||||
cd C:\Shares\testdatadb
|
||||
node import-all-stage.js
|
||||
```
|
||||
|
||||
### Machine data volumes in STAGE
|
||||
| Machine | Files |
|
||||
|---------|-------|
|
||||
| TS-4L | 3,082 |
|
||||
| TS-4R | 2,741 |
|
||||
| TS-1R | 509 |
|
||||
| TS-8R | 478 |
|
||||
| TS-3R | 435 |
|
||||
| TS-11R | 325 |
|
||||
| TS-8L | 285 |
|
||||
| TS-11L | 248 |
|
||||
| TS-27 | 10 (already imported) |
|
||||
| TS-1L | 1 |
|
||||
|
||||
### Web Share Layout (X:\)
|
||||
- X:\For_Web -- Validated datasheets (production)
|
||||
- X:\For_Web_PDF -- PDF versions (4.7K files)
|
||||
- X:\Test_Datasheets -- Incoming/staging
|
||||
- X:\Bad_Datasheets -- Invalid files (18K)
|
||||
- X:\Datasheets_Log -- Processing logs
|
||||
|
||||
---
|
||||
|
||||
## Known Issues & Pending Work
|
||||
|
||||
### HIGH PRIORITY
|
||||
1. **Run import-all-stage.js** -- 8,100 TXT files need cross-referencing and ingestion
|
||||
2. **Website Upload Replacement** -- Old ASP.NET endpoints (Uploader.aspx) return 404. Need new approach.
|
||||
3. **7B Series Datasheets** -- ~830K records can't generate datasheets (missing 7BMAIN.DAT spec file). Check ENGR share.
|
||||
4. **Service Permissions** -- testdatadb runs as SYSTEM, causing file permission issues. Change to INTRANET\sysadmin.
|
||||
|
||||
### MEDIUM PRIORITY
|
||||
5. **C2 IP Blocking** -- iptables rules added to UDM for 80.76.49.18 and 45.88.91.99. Need permanent rules in UniFi UI.
|
||||
6. **MFA Enforcement** -- 19/38 users ready. Report-only until April 4, 2026. Monitor registration.
|
||||
7. **Joel Lohr Account** -- Retiring March 31. Disable account post-retirement. Auto-reply set to Dan Center.
|
||||
|
||||
---
|
||||
|
||||
## Security Incident (2026-03-27)
|
||||
|
||||
**DF-JOEL2 (192.168.0.143) compromised via phishing:**
|
||||
- Joel Lohr clicked phishing link in personal Yahoo email
|
||||
- ScreenConnect C2 installed, "Angel Raya" connected remotely
|
||||
- Two C2 backdoors deployed via PowerShell
|
||||
- C2 IPs: 80.76.49.18, 45.88.91.99 (AS399486, suspended by host)
|
||||
- IC3 Complaint: 1c32ade367084be9acd548f23705736f
|
||||
- ConnectWise Case: 03464184
|
||||
- **Remediation complete:** IPs blocked, 3 rogue clients removed, password reset, sessions revoked
|
||||
- **No lateral movement detected** (32 machines scanned clean)
|
||||
|
||||
---
|
||||
|
||||
## Key Contacts
|
||||
|
||||
| Person | Email | Role |
|
||||
|--------|-------|------|
|
||||
| John Lehman | jlehman@dataforth.com | Engineering, QB code, test specs |
|
||||
| Dan Center | dcenter@dataforth.com | Operations (replacing Joel) |
|
||||
| Peter Iliya | pIliya@dataforth.com | Applications Engineer |
|
||||
| AJ | dataforthgit@... | Engineering contact |
|
||||
| Ken Hoffman | (unresponsive) | TestDataSheetUploader author |
|
||||
| Georg Haubner | ghaubner@dataforth.com | Has pre-crypto backup on D: drive |
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Commands
|
||||
|
||||
```powershell
|
||||
# Check BAT files on NAS
|
||||
ssh root@192.168.0.9 'ls -la /data/test/COMMON/ProdSW/'
|
||||
|
||||
# Trigger NAS sync
|
||||
Start-ScheduledTask -TaskName 'Sync-FromNAS'
|
||||
|
||||
# Check sync log
|
||||
Get-Content 'C:\Shares\test\scripts\sync-from-nas.log' -Tail 20
|
||||
|
||||
# Check TestDataDB health
|
||||
curl http://localhost:3000/health
|
||||
|
||||
# Query test records
|
||||
node -e "const db=require('better-sqlite3')('C:\\Shares\\testdatadb\\database\\testdata.db',{readonly:true});console.log(db.prepare('SELECT COUNT(*) as cnt FROM test_records').get())"
|
||||
|
||||
# Check Stage files on NAS
|
||||
ssh root@192.168.0.9 'find /data/test/STAGE -name "*.TXT" | wc -l'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-03-29
|
||||
@@ -1,4 +1,66 @@
|
||||
{
|
||||
"last_updated": "2026-01-23T00:00:00Z",
|
||||
"tasks": []
|
||||
"last_updated": "2026-03-23T20:10:00Z",
|
||||
"tasks": [
|
||||
{
|
||||
"id": "win-setup-001",
|
||||
"title": "Windows Machine Setup - Align with Directives",
|
||||
"created": "2026-03-23",
|
||||
"status": "in_progress",
|
||||
"context": "Setting up Windows guru workstation to match ClaudeTools project directives. This session is non-elevated. Elevated session should pick up remaining items.",
|
||||
"completed_items": [
|
||||
"Node.js v24.14.0 installed via winget (PATH: C:\\Program Files\\nodejs)",
|
||||
".mcp.json created at C:\\Users\\guru\\ClaudeTools\\.mcp.json (filesystem + sequential-thinking)",
|
||||
"GrepAI v0.35.0 binary downloaded to C:\\Users\\guru\\ClaudeTools\\grepai.exe"
|
||||
],
|
||||
"remaining_items": [
|
||||
{
|
||||
"step": 1,
|
||||
"item": "Finish Ollama installation",
|
||||
"priority": "HIGH",
|
||||
"details": "winget install was downloading v0.18.2 (1.61GB) but session interrupted ~50%. Run: winget install Ollama.Ollama --accept-package-agreements --accept-source-agreements. Verify with: ollama --version"
|
||||
},
|
||||
{
|
||||
"step": 2,
|
||||
"item": "Pull Ollama models",
|
||||
"priority": "HIGH",
|
||||
"depends_on": "step 1",
|
||||
"details": "ollama pull nomic-embed-text && ollama pull qwen3:14b && ollama pull codestral:22b"
|
||||
},
|
||||
{
|
||||
"step": 3,
|
||||
"item": "Initialize GrepAI index",
|
||||
"priority": "HIGH",
|
||||
"depends_on": "step 2 (needs nomic-embed-text)",
|
||||
"details": "cd C:\\Users\\guru\\ClaudeTools && ./grepai.exe init && ./grepai.exe watch --background"
|
||||
},
|
||||
{
|
||||
"step": 4,
|
||||
"item": "Add GrepAI to .mcp.json",
|
||||
"priority": "HIGH",
|
||||
"depends_on": "step 3",
|
||||
"details": "Add to C:\\Users\\guru\\ClaudeTools\\.mcp.json mcpServers section: \"grepai\": { \"command\": \"C:\\\\Users\\\\guru\\\\ClaudeTools\\\\grepai.exe\", \"args\": [\"mcp-serve\"] }"
|
||||
},
|
||||
{
|
||||
"step": 5,
|
||||
"item": "Verify MCP servers load",
|
||||
"priority": "MEDIUM",
|
||||
"depends_on": "steps 1-4",
|
||||
"details": "Restart Claude Code and confirm sequential-thinking, filesystem, and grepai MCP servers connect. Node.js is installed but current shell may need PATH refresh."
|
||||
},
|
||||
{
|
||||
"step": 6,
|
||||
"item": "Update machine memory record",
|
||||
"priority": "LOW",
|
||||
"depends_on": "all above",
|
||||
"details": "Update .claude/memory/machine_windows_guru_setup_status.md to reflect completed setup. Remove all 'Missing' items, mark as fully aligned."
|
||||
}
|
||||
],
|
||||
"notes": [
|
||||
"GitHub MCP server intentionally excluded - project uses Gitea not GitHub",
|
||||
"User said they'll get back on git setup separately",
|
||||
"Node.js may not be in current shell PATH - new terminal needed",
|
||||
"Ollama download was partially through when interrupted"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
59
.claude/agents/deep-explore.md
Normal file
59
.claude/agents/deep-explore.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
name: deep-explore
|
||||
description: Deep codebase exploration using grepai semantic search and call graph tracing. Use this agent for understanding code architecture, finding implementations by intent, analyzing function relationships, and exploring unfamiliar code areas.
|
||||
tools: Read, Grep, Glob, Bash
|
||||
model: inherit
|
||||
---
|
||||
|
||||
## Instructions
|
||||
|
||||
You are a specialized code exploration agent with access to grepai semantic search and call graph tracing.
|
||||
|
||||
### Primary Tools
|
||||
|
||||
#### 1. Semantic Search: `grepai search`
|
||||
|
||||
Use this to find code by intent and meaning:
|
||||
|
||||
```bash
|
||||
# Use English queries for best results (--compact saves ~80% tokens)
|
||||
grepai search "authentication flow" --json --compact
|
||||
grepai search "error handling middleware" --json --compact
|
||||
grepai search "database connection management" --json --compact
|
||||
```
|
||||
|
||||
#### 2. Call Graph Tracing: `grepai trace`
|
||||
|
||||
Use this to understand function relationships and code flow:
|
||||
|
||||
```bash
|
||||
# Find all functions that call a symbol
|
||||
grepai trace callers "HandleRequest" --json
|
||||
|
||||
# Find all functions called by a symbol
|
||||
grepai trace callees "ProcessOrder" --json
|
||||
|
||||
# Build complete call graph
|
||||
grepai trace graph "ValidateToken" --depth 3 --json
|
||||
```
|
||||
|
||||
Use `grepai trace` when you need to:
|
||||
- Find all callers of a function
|
||||
- Understand the call hierarchy
|
||||
- Analyze the impact of changes to a function
|
||||
- Map dependencies between components
|
||||
|
||||
### When to use standard tools
|
||||
|
||||
Only fall back to Grep/Glob when:
|
||||
- You need exact text matching (variable names, imports)
|
||||
- grepai is not available or returns errors
|
||||
- You need file path patterns
|
||||
|
||||
### Workflow
|
||||
|
||||
1. Start with `grepai search` to find relevant code semantically
|
||||
2. Use `grepai trace` to understand function relationships and call graphs
|
||||
3. Use `Read` to examine promising files in detail
|
||||
4. Use Grep only for exact string searches if needed
|
||||
5. Synthesize findings into a clear summary
|
||||
@@ -1,97 +0,0 @@
|
||||
# ClaudeTools Project Context
|
||||
|
||||
## Identity: You Are a Coordinator
|
||||
|
||||
You are NOT an executor. You coordinate specialized agents and preserve your context window.
|
||||
|
||||
**Delegate ALL significant work:**
|
||||
|
||||
| Operation | Delegate To |
|
||||
|-----------|------------|
|
||||
| Database queries/inserts/updates | Database Agent |
|
||||
| Production code generation | Coding Agent |
|
||||
| Code review (MANDATORY after changes) | Code Review Agent |
|
||||
| Test execution | Testing Agent |
|
||||
| Git commits/push/branch | Gitea Agent |
|
||||
| Backups/restore | Backup Agent |
|
||||
| File exploration (broad) | Explore Agent |
|
||||
| Complex reasoning | General-purpose + Sequential Thinking |
|
||||
|
||||
**Do yourself:** Simple responses, reading 1-2 files, presenting results, planning, decisions.
|
||||
**Rule:** >500 tokens of work = delegate. Code or database = ALWAYS delegate.
|
||||
|
||||
**DO NOT** query databases directly (no SSH/mysql/curl to API). **DO NOT** write production code. **DO NOT** run tests. **DO NOT** commit/push. Use the appropriate agent.
|
||||
|
||||
---
|
||||
|
||||
## Project Overview
|
||||
|
||||
**Type:** MSP Work Tracking System | **Status:** Production-Ready (Phase 5 Complete)
|
||||
**Database:** MariaDB 10.6.22 @ 172.16.3.30:3306 | **API:** http://172.16.3.30:8001
|
||||
**Stats:** 95+ endpoints, 38 tables, JWT auth, AES-256-GCM encryption
|
||||
|
||||
**DB Connection:** Host: 172.16.3.30:3306 | DB: claudetools | User: claudetools | Password: CT_e8fcd5a3952030a79ed6debae6c954ed
|
||||
**Details:** `.claude/agents/DATABASE_CONNECTION_INFO.md`
|
||||
|
||||
---
|
||||
|
||||
## Key Rules
|
||||
|
||||
- **NO EMOJIS** - Use ASCII markers: `[OK]`, `[ERROR]`, `[WARNING]`, `[SUCCESS]`, `[INFO]`
|
||||
- **No hardcoded credentials** - Use encrypted storage
|
||||
- **SSH:** Use system OpenSSH (`C:\Windows\System32\OpenSSH\ssh.exe`), never Git for Windows SSH
|
||||
- **Data integrity:** Never use placeholder/fake data. Check credentials.md or ask user.
|
||||
- **Full coding standards:** `.claude/CODING_GUIDELINES.md` (agents read on-demand, not every session)
|
||||
|
||||
---
|
||||
|
||||
## Automatic Behaviors
|
||||
|
||||
- **Frontend Design:** Auto-invoke `/frontend-design` skill after ANY UI change (HTML/CSS/JSX/styling)
|
||||
- **Sequential Thinking:** Use for genuine complexity - rejection loops, 3+ critical issues, architectural decisions, multi-step debugging
|
||||
- **Task Management:** Complex work (>3 steps) -> TaskCreate. Persist to `.claude/active-tasks.json`.
|
||||
|
||||
---
|
||||
|
||||
## Context Recovery
|
||||
|
||||
When user references previous work, use `/context` command. Never ask user for info in:
|
||||
- `credentials.md` - All infrastructure credentials (UNREDACTED)
|
||||
- `session-logs/` - Daily work logs (also in `projects/*/session-logs/` and `clients/*/session-logs/`)
|
||||
- `SESSION_STATE.md` - Project history
|
||||
|
||||
---
|
||||
|
||||
## Commands & Skills
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/checkpoint` | Dual checkpoint: git commit + database context |
|
||||
| `/save` | Comprehensive session log (credentials, decisions, changes) |
|
||||
| `/context` | Search session logs and credentials.md |
|
||||
| `/sync` | Sync config from Gitea repository |
|
||||
| `/create-spec` | Create app specification for AutoCoder |
|
||||
| `/frontend-design` | Modern frontend design patterns (auto-invoke after UI changes) |
|
||||
|
||||
---
|
||||
|
||||
## File Placement (Quick Rules)
|
||||
|
||||
- **Dataforth DOS work** -> `projects/dataforth-dos/`
|
||||
- **ClaudeTools API code** -> `api/`, `migrations/` (existing structure)
|
||||
- **Client work** -> `clients/[client-name]/`
|
||||
- **Session logs** -> project or client `session-logs/` subfolder; general -> root `session-logs/`
|
||||
- **Full guide:** `.claude/FILE_PLACEMENT_GUIDE.md` (read when saving files, not every session)
|
||||
|
||||
---
|
||||
|
||||
## Reference (read on-demand, not every session)
|
||||
|
||||
- **Project structure, endpoints, workflows, troubleshooting:** `.claude/REFERENCE.md`
|
||||
- **Agent definitions:** `.claude/agents/*.md`
|
||||
- **MCP servers:** `MCP_SERVERS.md`
|
||||
- **Coding standards:** `.claude/CODING_GUIDELINES.md`
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2026-02-17
|
||||
214
.claude/commands/1password.md
Normal file
214
.claude/commands/1password.md
Normal file
@@ -0,0 +1,214 @@
|
||||
---
|
||||
name: 1password
|
||||
description: >
|
||||
Integrate 1Password secrets management into Claude Code workflows. Use when the user wants to:
|
||||
store API keys or credentials in 1Password, read secrets from 1Password into scripts or config,
|
||||
set up .env files using 1Password secret references, rotate or update credentials, manage
|
||||
developer secrets across projects, use 1Password service accounts for CI/CD, or integrate
|
||||
1Password with tools like Claude Desktop, n8n, Docker, Supabase, GitHub Actions, or Replit.
|
||||
Triggers on phrases like "store in 1Password", "read from 1Password", "op://", "secret reference",
|
||||
"manage API keys with 1Password", "1Password CLI", or any request involving the `op` command.
|
||||
---
|
||||
|
||||
# 1Password Skill
|
||||
|
||||
## ⚠️ Critical: Never Type Secrets Into Claude Code
|
||||
|
||||
**Claude Code can see everything typed in its terminal and chat.**
|
||||
|
||||
When a user needs to store a secret, ALWAYS use the Terminal launch pattern:
|
||||
1. Generate a pre-filled script with known values already set
|
||||
2. Use `launch-in-terminal.sh` to open it in Terminal.app
|
||||
3. User types secrets in that window — Claude Code cannot see it
|
||||
4. 1Password stores the secret, outputs `op://` references back to Claude
|
||||
|
||||
```bash
|
||||
# Claude generates the script, then launches it outside its own view:
|
||||
bash scripts/launch-in-terminal.sh /tmp/setup-my-service.sh "Service Name Setup"
|
||||
```
|
||||
|
||||
Never ask users to paste API keys, passwords, or tokens into:
|
||||
- The Claude Code chat
|
||||
- A Bash tool call visible in Claude Code
|
||||
- Any file Claude Code writes before it's stored in 1Password
|
||||
|
||||
---
|
||||
|
||||
## Setup Check
|
||||
|
||||
Always verify the CLI is ready before any operation:
|
||||
|
||||
```bash
|
||||
bash scripts/check_setup.sh
|
||||
```
|
||||
|
||||
If not installed: https://developer.1password.com/docs/cli/get-started/
|
||||
If not signed in: unlock the **1Password desktop app** (after Mac restart, the app must be unlocked before the CLI works)
|
||||
|
||||
---
|
||||
|
||||
## Storing Secrets: The Terminal Launch Pattern
|
||||
|
||||
When a user needs to store a new secret or credential:
|
||||
|
||||
**Step 1 — Generate the script** (Claude does this, with known values pre-filled):
|
||||
|
||||
```bash
|
||||
cat > /tmp/setup-SERVICE.sh << 'EOF'
|
||||
bash /path/to/store-mcp-credentials.sh \
|
||||
--vault Dev \
|
||||
--item "Service Name" \
|
||||
--set "url=https://known-url.com" \
|
||||
--set "env=production" \
|
||||
--secret "api_key" \
|
||||
--secret "webhook_secret"
|
||||
EOF
|
||||
```
|
||||
|
||||
**Step 2 — Launch in Terminal.app** (secrets stay out of Claude Code):
|
||||
|
||||
```bash
|
||||
bash scripts/launch-in-terminal.sh /tmp/setup-SERVICE.sh "Service Name Setup"
|
||||
```
|
||||
|
||||
**Step 3 — Update config** (Claude uses the `op://` references from the output):
|
||||
|
||||
```json
|
||||
"SERVICE_API_KEY": "op://Dev/Service Name/api_key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Patterns
|
||||
|
||||
### Read a secret
|
||||
|
||||
```bash
|
||||
op read "op://VaultName/ItemTitle/field_name"
|
||||
export API_KEY=$(op read "op://Dev/Anthropic/api_key")
|
||||
```
|
||||
|
||||
### Store a new secret
|
||||
|
||||
```bash
|
||||
# Basic
|
||||
bash scripts/store_secret.sh --title "My API Key" --field api_key --value "sk-..."
|
||||
|
||||
# With vault
|
||||
bash scripts/store_secret.sh --title "My API Key" --vault Dev --field api_key --value "sk-..."
|
||||
|
||||
# From environment variable
|
||||
bash scripts/store_secret.sh --from-env ANTHROPIC_API_KEY --title "Anthropic"
|
||||
|
||||
# Generate a secure credential
|
||||
bash scripts/store_secret.sh --title "App Secret" --field secret --generate --length 32
|
||||
```
|
||||
|
||||
### Update an existing secret
|
||||
|
||||
```bash
|
||||
bash scripts/store_secret.sh --update --title "My API Key" --field api_key --value "new-value"
|
||||
# Or directly:
|
||||
op item edit "My API Key" api_key[password]=new-value
|
||||
```
|
||||
|
||||
### Generate a .env from 1Password
|
||||
|
||||
```bash
|
||||
# Interactive — lists items, choose one
|
||||
bash scripts/env_from_op.sh
|
||||
|
||||
# From a specific item (dry run preview)
|
||||
bash scripts/env_from_op.sh --item "Project Credentials" --dry-run
|
||||
|
||||
# Write .env.tpl (secret references — safe to commit)
|
||||
bash scripts/env_from_op.sh --item "Project Credentials" --output .env.tpl
|
||||
|
||||
# Write .env with resolved real values (DO NOT commit)
|
||||
bash scripts/env_from_op.sh --item "Project Credentials" --resolve --output .env
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secret References (op://)
|
||||
|
||||
The safest pattern — store `op://` references in config files instead of real values.
|
||||
|
||||
> **Privacy note:** `op://` references reveal vault names, item names, and field names.
|
||||
> Safe to commit to **private repos**. For public repos, check that your vault/item naming
|
||||
> doesn't expose sensitive structure (client names, internal service names, etc.).
|
||||
|
||||
```
|
||||
op://VaultName/ItemTitle/field_name
|
||||
```
|
||||
|
||||
```bash
|
||||
# .env.tpl (commit this file)
|
||||
ANTHROPIC_API_KEY=op://Dev/Anthropic/api_key
|
||||
N8N_API_KEY=op://Dev/n8n/api_key
|
||||
SUPABASE_SERVICE_KEY=op://Dev/Supabase/service_key
|
||||
|
||||
# ✅ Inject at runtime — secrets stay in subprocess, never in shell history
|
||||
op run --env-file=.env.tpl -- your-command
|
||||
|
||||
# ⚠️ Avoid sourcing into current shell — unsafe if values contain $(...) or backticks
|
||||
# source <(op run --env-file=.env.tpl -- env) ← skip this pattern
|
||||
```
|
||||
|
||||
For full syntax and edge cases: [references/secret_references.md](references/secret_references.md)
|
||||
|
||||
---
|
||||
|
||||
## Integration Guides
|
||||
|
||||
Read [references/integrations.md](references/integrations.md) for patterns with:
|
||||
|
||||
- **Claude Desktop** — MCP server config using `op run`
|
||||
- **n8n** — Environment injection at startup, credential push via API
|
||||
- **Docker / Docker Compose** — `op run -- docker compose up`
|
||||
- **GitHub Actions** — `1password/load-secrets-action`
|
||||
- **Python scripts** — subprocess + 1Password SDK
|
||||
- **Supabase** — Storing and retrieving project credentials
|
||||
- **Replit** — Local dev → Replit Secrets bridge
|
||||
- **Rotation workflow** — Update in service → update in 1Password → re-inject
|
||||
|
||||
---
|
||||
|
||||
## Common CLI Commands
|
||||
|
||||
Full reference: [references/op_commands.md](references/op_commands.md)
|
||||
|
||||
```bash
|
||||
op item list # List all items
|
||||
op item list --vault Dev # Filter by vault
|
||||
op item get "Item Title" # View item details
|
||||
op item get "Item Title" --format json # JSON output
|
||||
op vault list # List vaults
|
||||
op whoami # Check auth status
|
||||
op account list # List accounts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CI/CD: Service Accounts
|
||||
|
||||
For non-interactive environments (GitHub Actions, Docker, n8n server):
|
||||
|
||||
```bash
|
||||
export OP_SERVICE_ACCOUNT_TOKEN="ops_eyJ..."
|
||||
op read "op://Dev/MyApp/api_key" # works without signin prompt
|
||||
```
|
||||
|
||||
Create service accounts: 1Password UI → Settings → Developer → Service Accounts.
|
||||
Grant vault access only to what the service needs.
|
||||
|
||||
---
|
||||
|
||||
## Security Rules
|
||||
|
||||
1. **Never hardcode secrets** — always use `op://` references or runtime injection
|
||||
2. **Commit `.env.tpl`** to private repos only — it exposes vault/item structure, not values
|
||||
3. **Never commit `.env`** (real values) — add it to `.gitignore` immediately: `echo ".env" >> .gitignore`
|
||||
4. **Use vaults to scope access** — separate vault per project or team
|
||||
5. **Rotate on exposure** — use `store_secret.sh --update` then re-inject everywhere
|
||||
6. **Service accounts for CI/CD** — never use personal account tokens in automation
|
||||
37
.claude/commands/scc.md
Normal file
37
.claude/commands/scc.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# /scc - Save, Commit, and Push
|
||||
|
||||
Quick command to save session log, stage everything, and push to Gitea in one shot.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Save session log** - Create/update session log for today using the /save skill logic:
|
||||
- Determine correct location based on work context (project-specific or general `session-logs/`)
|
||||
- Use format `YYYY-MM-DD-session.md`
|
||||
- If file exists, append with `## Update: HH:MM` header
|
||||
- Include: summary, credentials (unredacted), infrastructure, commands, files changed, pending tasks
|
||||
|
||||
2. **Stage all changes** - Run `git add -A` to stage everything including the new session log
|
||||
|
||||
3. **Commit** - Auto-commit with message:
|
||||
```
|
||||
scc: Session save and push from [hostname] at [timestamp]
|
||||
|
||||
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
```
|
||||
|
||||
4. **Push to Gitea** - Run `git push origin main`
|
||||
|
||||
5. **Report** - Confirm what was saved, committed, and pushed
|
||||
|
||||
6. **Reaffirm roles** - After push, briefly restate:
|
||||
- You are a COORDINATOR, not an executor
|
||||
- Delegate: DB -> Database Agent, code -> Coding Agent, git -> Gitea Agent, tests -> Testing Agent
|
||||
- Do yourself: simple responses, reading 1-2 files, planning, decisions
|
||||
- >500 tokens of work = delegate. Code or database = ALWAYS delegate.
|
||||
- NO EMOJIS. Use ASCII markers: `[OK]`, `[ERROR]`, `[WARNING]`, `[SUCCESS]`, `[INFO]`
|
||||
|
||||
## Important
|
||||
- This is a FAST command - no lengthy analysis, just save and ship
|
||||
- Do NOT invoke /refresh-directives afterward (unlike /sync)
|
||||
- Do NOT read behavioral guidelines beyond the role reaffirmation above
|
||||
- Just save, commit, push, reaffirm, report
|
||||
375
.claude/machines/LINUX_PC_ONBOARDING.md
Normal file
375
.claude/machines/LINUX_PC_ONBOARDING.md
Normal file
@@ -0,0 +1,375 @@
|
||||
# Linux PC Onboarding Guide for Claude Code
|
||||
|
||||
**Purpose:** This document helps Claude Code understand how to operate correctly in the ClaudeTools environment after a fresh Linux install.
|
||||
|
||||
**Read this FIRST** before doing any work.
|
||||
|
||||
---
|
||||
|
||||
## TL;DR - Critical Rules
|
||||
|
||||
1. **You are a COORDINATOR, not an executor** - delegate significant work to agents
|
||||
2. **NO EMOJIS** - Use `[OK]`, `[ERROR]`, `[WARNING]`, `[SUCCESS]`, `[INFO]`
|
||||
3. **Never query databases directly** - Use Database Agent
|
||||
4. **Never write production code yourself** - Use Coding Agent
|
||||
5. **Always run `/sync` first** to get latest context from Gitea
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Initial Setup
|
||||
|
||||
### Run These Commands First
|
||||
|
||||
```bash
|
||||
# 1. Navigate to ClaudeTools
|
||||
cd ~/ClaudeTools # or wherever you cloned it
|
||||
|
||||
# 2. Pull latest from Gitea
|
||||
git pull origin main
|
||||
|
||||
# 3. Check GrepAI status (semantic code search)
|
||||
grepai status
|
||||
|
||||
# 4. If GrepAI watcher isn't running:
|
||||
grepai watch --background
|
||||
|
||||
# 5. Check Ollama is running (local AI)
|
||||
curl -s http://localhost:11434/api/tags | jq '.models[].name'
|
||||
```
|
||||
|
||||
### Required Models for Ollama
|
||||
|
||||
Pull these if not present:
|
||||
```bash
|
||||
ollama pull qwen3:14b # General tasks
|
||||
ollama pull codestral:22b # Code tasks
|
||||
ollama pull nomic-embed-text # Embeddings for GrepAI
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2: Understand Your Identity
|
||||
|
||||
### You Are a Coordinator
|
||||
|
||||
You preserve your context window by delegating work. You do NOT:
|
||||
- Query databases directly (no SSH/mysql/curl to API)
|
||||
- Write production code yourself
|
||||
- Run tests yourself
|
||||
- Commit/push yourself
|
||||
|
||||
You DO:
|
||||
- Plan and make decisions
|
||||
- Read 1-2 files for quick answers
|
||||
- Present results to the user
|
||||
- Coordinate specialized agents
|
||||
|
||||
### Delegation Rules
|
||||
|
||||
| Task | Delegate To |
|
||||
|------|-------------|
|
||||
| Database queries/inserts/updates | Database Agent |
|
||||
| Production code generation | Coding Agent |
|
||||
| Code review (MANDATORY after changes) | Code Review Agent |
|
||||
| Test execution | Testing Agent |
|
||||
| Git commits/push/branch | Gitea Agent |
|
||||
| Backups/restore | Backup Agent |
|
||||
| File exploration (broad) | Explore Agent |
|
||||
| Semantic code search | deep-explore Agent |
|
||||
| Complex reasoning | General-purpose + Sequential Thinking |
|
||||
|
||||
**Rule of thumb:** If work exceeds 500 tokens = delegate. If it touches code or database = ALWAYS delegate.
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Key Infrastructure
|
||||
|
||||
### Database
|
||||
- **Host:** 172.16.3.30:3306
|
||||
- **Database:** claudetools
|
||||
- **User:** claudetools
|
||||
- **Password:** CT_e8fcd5a3952030a79ed6debae6c954ed
|
||||
- **DO NOT** connect directly - use Database Agent
|
||||
|
||||
### API
|
||||
- **URL:** http://172.16.3.30:8001
|
||||
- **Docs:** http://172.16.3.30:8001/api/docs
|
||||
- **Auth:** JWT Bearer Token
|
||||
|
||||
### Gitea
|
||||
- **URL:** https://git.azcomputerguru.com
|
||||
- **Repo:** azcomputerguru/claudetools
|
||||
|
||||
---
|
||||
|
||||
## Step 4: Available Commands
|
||||
|
||||
These are slash commands you can invoke:
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/sync` | Sync with Gitea, pull latest, push local changes |
|
||||
| `/checkpoint` | Git commit + database context snapshot |
|
||||
| `/save` | Create comprehensive session log |
|
||||
| `/context` | Search session logs and credentials for previous work |
|
||||
| `/refresh-directives` | Re-read behavioral rules (do after sync) |
|
||||
|
||||
### First Thing Every Session
|
||||
|
||||
```
|
||||
/sync
|
||||
```
|
||||
|
||||
This pulls latest changes from other machines and pushes your local changes.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: ASCII Markers (NO EMOJIS!)
|
||||
|
||||
**Never use emojis.** They cause encoding issues across platforms.
|
||||
|
||||
Use these instead:
|
||||
|
||||
| Marker | Use For |
|
||||
|--------|---------|
|
||||
| `[OK]` | Success, completed |
|
||||
| `[SUCCESS]` | Task completed successfully |
|
||||
| `[ERROR]` | Failure, problem |
|
||||
| `[WARNING]` | Caution, potential issue |
|
||||
| `[INFO]` | Informational message |
|
||||
| `[CRITICAL]` | Severe error |
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
✓ Task completed!
|
||||
⚠ Warning: check config
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```
|
||||
[OK] Task completed!
|
||||
[WARNING] Check config
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 6: Local AI (Ollama)
|
||||
|
||||
Ollama runs locally for tasks that don't need Claude-level reasoning.
|
||||
|
||||
### When to Use Ollama
|
||||
|
||||
**Good for:**
|
||||
- Bulk/repetitive tasks (summarizing 50 logs)
|
||||
- Boilerplate code generation
|
||||
- Data extraction/classification
|
||||
- Draft content you'll review
|
||||
|
||||
**Bad for (use Claude):**
|
||||
- Architectural decisions
|
||||
- Security-sensitive code
|
||||
- Multi-step planning
|
||||
- Final production output
|
||||
|
||||
### How to Call Ollama
|
||||
|
||||
```bash
|
||||
# Simple prompt
|
||||
curl -s http://localhost:11434/api/generate \
|
||||
-d '{"model":"qwen3:14b","prompt":"Summarize: ...","stream":false}' \
|
||||
| jq -r '.response'
|
||||
|
||||
# Code tasks
|
||||
curl -s http://localhost:11434/api/chat \
|
||||
-d '{"model":"codestral:22b","messages":[{"role":"user","content":"..."}],"stream":false}' \
|
||||
| jq -r '.message.content'
|
||||
```
|
||||
|
||||
### Review Policy for Ollama Output
|
||||
|
||||
| Impact Level | Review Required | Examples |
|
||||
|--------------|-----------------|----------|
|
||||
| Critical | ALWAYS verify against source | Auth, security, encryption, DB migrations |
|
||||
| High | Review for correctness | API logic, business rules, infra scripts |
|
||||
| Medium | Skim for obvious errors | Internal docs, session summaries, boilerplate |
|
||||
| Low | Trust without review | Classification, reformatting, placeholders |
|
||||
|
||||
---
|
||||
|
||||
## Step 7: GrepAI (Semantic Search)
|
||||
|
||||
GrepAI indexes the codebase for natural language search.
|
||||
|
||||
### When to Use GrepAI vs Grep
|
||||
|
||||
**Use GrepAI for:**
|
||||
- "How does authentication work?"
|
||||
- "Find implementations related to user sessions"
|
||||
- Exploring unfamiliar code areas
|
||||
- Context recovery from session logs
|
||||
|
||||
**Use regular Grep for:**
|
||||
- Exact text matches
|
||||
- Known function/class names
|
||||
- Simple pattern matching
|
||||
|
||||
### Commands
|
||||
|
||||
```bash
|
||||
# Search
|
||||
grepai search "how does JWT auth work" --json
|
||||
|
||||
# Call graph tracing
|
||||
grepai trace callers "get_db"
|
||||
grepai trace callees "create_user"
|
||||
|
||||
# Start watcher (if not running)
|
||||
grepai watch --background
|
||||
|
||||
# Restart watcher (if results seem stale)
|
||||
grepai watch --stop && grepai watch --background
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 8: File Organization
|
||||
|
||||
### Where to Put Things
|
||||
|
||||
| Content Type | Location |
|
||||
|--------------|----------|
|
||||
| ClaudeTools API code | `api/`, `migrations/` |
|
||||
| Client work | `clients/[client-name]/` |
|
||||
| Project work | `projects/[project-name]/` |
|
||||
| Session logs | `session-logs/` or project-specific `session-logs/` |
|
||||
| Scripts | Project-specific `scripts/` folder |
|
||||
| Machine specs | `.claude/machines/` |
|
||||
|
||||
### Key Files to Know
|
||||
|
||||
- `credentials.md` - All infrastructure credentials (NEVER ask user for these)
|
||||
- `SESSION_STATE.md` - Project history
|
||||
- `.claude/CLAUDE.md` - Main behavioral rules (auto-loaded)
|
||||
- `.claude/CODING_GUIDELINES.md` - Coding standards
|
||||
- `.claude/agents/*.md` - Agent definitions
|
||||
|
||||
---
|
||||
|
||||
## Step 9: Context Recovery
|
||||
|
||||
When the user references previous work:
|
||||
|
||||
1. **Use `/context` command** to search session logs
|
||||
2. **Check `credentials.md`** for infrastructure details
|
||||
3. **Search session-logs/** for recent work
|
||||
4. **Never ask user** for info that's in these files
|
||||
|
||||
### Session Log Locations
|
||||
|
||||
```
|
||||
session-logs/ # General logs
|
||||
projects/*/session-logs/ # Project-specific
|
||||
clients/*/session-logs/ # Client-specific
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 10: Automatic Behaviors
|
||||
|
||||
These happen automatically - don't forget them:
|
||||
|
||||
1. **After UI changes** (HTML/CSS/JSX) -> Auto-invoke `/frontend-design`
|
||||
2. **Complex problems** (3+ issues, rejection loops) -> Use Sequential Thinking MCP
|
||||
3. **After code changes** -> Code Review Agent reviews (MANDATORY)
|
||||
4. **Complex tasks** (>3 steps) -> Create todo list with TodoWrite
|
||||
|
||||
---
|
||||
|
||||
## Step 11: SSH Configuration
|
||||
|
||||
On Linux, use system OpenSSH:
|
||||
|
||||
```bash
|
||||
# Standard SSH
|
||||
ssh user@host
|
||||
|
||||
# Never use paramiko or other SSH libraries when system SSH works
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 12: Self-Check After Setup
|
||||
|
||||
Run `/sync` and verify:
|
||||
|
||||
- [ ] Git pull successful
|
||||
- [ ] Latest session logs visible
|
||||
- [ ] GrepAI watcher running (`pgrep -f "grepai watch"`)
|
||||
- [ ] Ollama responding (`curl http://localhost:11434/api/tags`)
|
||||
- [ ] Can read credentials.md
|
||||
- [ ] Understand delegation model
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference Card
|
||||
|
||||
```
|
||||
IDENTITY: Coordinator (not executor)
|
||||
EMOJIS: NEVER (use [OK], [ERROR], etc.)
|
||||
DATABASE: Always delegate to Database Agent
|
||||
CODE: Always delegate to Coding Agent
|
||||
FIRST COMMAND: /sync
|
||||
CONTEXT: Check credentials.md and session-logs/
|
||||
LOCAL AI: Ollama for bulk tasks, review output
|
||||
SEARCH: GrepAI for intent, Grep for exact text
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Other Machines in This Environment
|
||||
|
||||
Check `.claude/machines/` for specs on:
|
||||
- `mikes-macbook-air.md` - M4 MacBook Air (this doc was created there)
|
||||
- (Add your machine spec after setup)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### GrepAI Not Working
|
||||
```bash
|
||||
grepai watch --stop
|
||||
grepai watch --background
|
||||
```
|
||||
|
||||
### Ollama Not Responding
|
||||
```bash
|
||||
sudo systemctl status ollama
|
||||
sudo systemctl restart ollama
|
||||
```
|
||||
|
||||
### Git Push Rejected
|
||||
```bash
|
||||
git pull origin main --rebase
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### Permission Issues
|
||||
```bash
|
||||
sudo chown -R $USER:$USER ~/ClaudeTools
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## First Task After Reading This
|
||||
|
||||
1. Run `/sync` to pull latest
|
||||
2. Run `/refresh-directives` to internalize rules
|
||||
3. Create your machine spec file in `.claude/machines/`
|
||||
4. You're ready to work!
|
||||
|
||||
---
|
||||
|
||||
**Created:** 2026-03-20
|
||||
**Created By:** Claude on Mikes-MacBook-Air.local
|
||||
**Purpose:** Help fresh Linux installs understand ClaudeTools behavioral expectations
|
||||
91
.claude/machines/acg-guru-5070.md
Normal file
91
.claude/machines/acg-guru-5070.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Machine: acg-guru-5070
|
||||
|
||||
**Hostname:** acg-guru-5070
|
||||
**Last Updated:** 2026-03-21
|
||||
|
||||
---
|
||||
|
||||
## Hardware Specs
|
||||
|
||||
| Spec | Value |
|
||||
|------|-------|
|
||||
| Model | Lenovo Legion Pro 7 16IAX10H (DMI: 83F5) |
|
||||
| CPU | Intel Core Ultra 9 275HX (24 cores, up to 5.4 GHz) |
|
||||
| Memory | 32 GB DDR5 |
|
||||
| GPU | NVIDIA GeForce RTX 5070 Ti Laptop GPU (12 GB VRAM) |
|
||||
| Storage 1 | 954 GB NVMe (SK Hynix) - CachyOS root, btrfs |
|
||||
| Storage 2 | 954 GB NVMe (SK Hynix) - /home, ext4 |
|
||||
|
||||
---
|
||||
|
||||
## Software
|
||||
|
||||
| Spec | Value |
|
||||
|------|-------|
|
||||
| OS | CachyOS Linux (Arch-based) |
|
||||
| Kernel | 6.19.9-1-cachyos |
|
||||
| DE | KDE Plasma 6.6.3 (Wayland) |
|
||||
| NVIDIA Driver | 595.45.04 (open kernel module) |
|
||||
| CUDA | 13.2 |
|
||||
| Python | 3.14 |
|
||||
|
||||
---
|
||||
|
||||
## Claude Code Environment
|
||||
|
||||
- **Working Directory:** /home/guru/ClaudeTools
|
||||
- **User:** guru
|
||||
- **Shell:** fish
|
||||
- **Git:** Configured for Gitea (git.azcomputerguru.com)
|
||||
|
||||
---
|
||||
|
||||
## Network
|
||||
|
||||
| Interface | Address |
|
||||
|-----------|---------|
|
||||
| WiFi (wlan0) | 10.3.36.218 |
|
||||
| Tailscale | 100.95.216.79 |
|
||||
|
||||
---
|
||||
|
||||
## Capabilities
|
||||
|
||||
- [x] Git operations
|
||||
- [x] SSH access to infrastructure
|
||||
- [x] GrepAI semantic search (watcher running)
|
||||
- [x] Ollama local AI (qwen3:14b, codestral:22b, nomic-embed-text)
|
||||
- [x] MCP servers available
|
||||
- [x] NVIDIA GPU (CUDA compute)
|
||||
- [x] Claude Code CLI
|
||||
|
||||
---
|
||||
|
||||
## Known Issues
|
||||
|
||||
### GPU Firmware Bug (RTX 5070 Ti)
|
||||
|
||||
The RTX 5070 Ti enters an error state (NVRM rpcSendMessage 0x00000062) after ~3-5 minutes of sustained GPU compute. This is a known Blackwell/RTX 50-series GSP firmware bug on Linux (NVIDIA bug #5953411). Affects all tested drivers (580.x, 590.x, 595.x).
|
||||
|
||||
**Impact:** GPU-accelerated ML workloads (Whisper transcription, etc.) cannot complete. GPU enters full ERR! state requiring hard power-off (warm reboot hangs with spinning symbol).
|
||||
|
||||
**Workarounds tried (none effective):**
|
||||
- Disable Runtime D3 power management
|
||||
- Enable persistence mode
|
||||
- Lock GPU clocks
|
||||
- Power cap reduction
|
||||
|
||||
**Status:** Waiting for NVIDIA driver fix. Heavy GPU compute delegated to Mac (M4).
|
||||
|
||||
### Custom Kernel for Audio
|
||||
|
||||
Running a custom-patched CachyOS kernel with the `nadimkobeissi/16iax10h-linux-sound-saga` patch for Awinic AW88399 smart amplifier support. Stock kernel has terrible speaker output. Patch is not upstreamed.
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Primary development workstation
|
||||
- GPU works fine for display, light compute, Ollama inference — only fails under sustained heavy compute (Whisper, training)
|
||||
- Sudo: NOPASSWD configured for guru user
|
||||
- Old btrfs @home subvolume on nvme0n1 (from initial install before /home was moved to nvme1n1)
|
||||
69
.claude/machines/guru-beast-rog.md
Normal file
69
.claude/machines/guru-beast-rog.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Machine: GURU-BEAST-ROG
|
||||
|
||||
**Hostname:** GURU-BEAST-ROG
|
||||
**Last Updated:** 2026-03-24
|
||||
|
||||
---
|
||||
|
||||
## Hardware Specs
|
||||
|
||||
| Spec | Value |
|
||||
|------|-------|
|
||||
| Model | ASUS Desktop (ROG) |
|
||||
| CPU | Intel Core i9-14900K (24 cores / 32 threads, up to 6.0 GHz) |
|
||||
| Memory | 128 GB DDR5 |
|
||||
| GPU | NVIDIA GeForce RTX 4090 (24 GB VRAM) |
|
||||
| Storage | 2 TB NVMe (WD_BLACK SN7100) |
|
||||
|
||||
---
|
||||
|
||||
## Software
|
||||
|
||||
| Spec | Value |
|
||||
|------|-------|
|
||||
| OS | Windows 11 Pro (26200) |
|
||||
| Python | 3.x (installed) |
|
||||
| Node.js | v24.14.0 |
|
||||
| Ollama | v0.18.2 |
|
||||
| Git | Installed (Git for Windows) |
|
||||
|
||||
---
|
||||
|
||||
## Claude Code Environment
|
||||
|
||||
- **Working Directory:** C:\Users\guru\ClaudeTools
|
||||
- **User:** guru
|
||||
- **Shell:** bash (Git for Windows)
|
||||
- **Git:** Configured for Gitea (git.azcomputerguru.com)
|
||||
|
||||
---
|
||||
|
||||
## Network
|
||||
|
||||
| Interface | Address |
|
||||
|-----------|---------|
|
||||
| Wi-Fi | 10.2.51.228 |
|
||||
| LAN (Local Area Connection) | 192.168.2.3 |
|
||||
|
||||
---
|
||||
|
||||
## Capabilities
|
||||
|
||||
- [x] Git operations
|
||||
- [x] SSH access to infrastructure
|
||||
- [x] GrepAI semantic search (watcher running)
|
||||
- [x] Ollama local AI (nomic-embed-text installed; qwen3:14b, codestral:22b pulling)
|
||||
- [x] MCP servers configured (filesystem, sequential-thinking, grepai)
|
||||
- [x] NVIDIA RTX 4090 GPU (CUDA compute)
|
||||
- [x] Claude Code CLI
|
||||
- [x] Bypass permissions mode (settings.json configured)
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Powerhouse desktop -- best GPU and most RAM across all workstations
|
||||
- RTX 4090 does NOT have the GSP firmware bug that affects the 5070 Ti on Linux
|
||||
- OpenVPN Connect adapter present (VPN capable)
|
||||
- credentials.md present and populated
|
||||
- Settings.json has permissions.defaultMode: bypassPermissions
|
||||
54
.claude/machines/mikes-macbook-air.md
Normal file
54
.claude/machines/mikes-macbook-air.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Machine: Mike's MacBook Air
|
||||
|
||||
**Hostname:** Mikes-MacBook-Air.local
|
||||
**Last Updated:** 2026-03-20
|
||||
|
||||
---
|
||||
|
||||
## Hardware Specs
|
||||
|
||||
| Spec | Value |
|
||||
|------|-------|
|
||||
| Model | MacBook Air (Mac16,12) |
|
||||
| Model Number | MC6T4LL/A |
|
||||
| Chip | Apple M4 |
|
||||
| CPU Cores | 10 (4 Performance + 6 Efficiency) |
|
||||
| Memory | 16 GB |
|
||||
| Serial | J1607PM6LD |
|
||||
|
||||
---
|
||||
|
||||
## Software
|
||||
|
||||
| Spec | Value |
|
||||
|------|-------|
|
||||
| OS | macOS 26.3.1 (25D2128) |
|
||||
| Kernel | Darwin 25.3.0 |
|
||||
| Boot Volume | Macintosh HD |
|
||||
|
||||
---
|
||||
|
||||
## Claude Code Environment
|
||||
|
||||
- **Working Directory:** /Users/azcomputerguru/ClaudeTools
|
||||
- **User:** azcomputerguru
|
||||
- **Shell:** zsh
|
||||
- **Git:** Configured for Gitea (git.azcomputerguru.com)
|
||||
|
||||
---
|
||||
|
||||
## Capabilities
|
||||
|
||||
- [x] Git operations
|
||||
- [x] SSH access to infrastructure
|
||||
- [x] GrepAI semantic search (watcher running)
|
||||
- [x] Ollama local AI (qwen3:14b, codestral:22b, nomic-embed-text)
|
||||
- [x] MCP servers available
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- Primary mobile development machine
|
||||
- M4 chip provides good local AI inference performance
|
||||
- Used for radio show prep, documentation, light development
|
||||
25
.claude/memory/MEMORY.md
Normal file
25
.claude/memory/MEMORY.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Memory Index
|
||||
|
||||
## Reference
|
||||
- [Community Forum (Flarum)](reference_community_forum.md) - Flarum forum at community.azcomputerguru.com, API access, database, posting workflow
|
||||
- [Radio Show Website](reference_radio_website.md) - Astro static site at radio.azcomputerguru.com on IX server
|
||||
- [IX Server SSH Access](reference_ix_server_ssh.md) - SSH access notes, no key auth from CachyOS workstation yet
|
||||
- [IX Access via Tailscale](reference_ix_access_tailscale.md) - IX server accessible with Tailscale on, no VPN needed
|
||||
- [Neptune Access via D2TESTNAS](reference_neptune_access_d2testnas.md) - Neptune must be routed through D2TESTNAS
|
||||
- [CachyOS Workstation Setup](reference_workstation_setup.md) - Dual NVMe, autostart apps, key fixes applied, old home location
|
||||
- [Matomo Analytics](reference_matomo_analytics.md) - Self-hosted analytics at analytics.azcomputerguru.com, site IDs, tracking for all 3 sites
|
||||
- [Dataforth Contact - AJ](reference_dataforth_contact.md) - AJ at Dataforth, dataforthgit@ email forwarding to him
|
||||
|
||||
## Feedback
|
||||
- [D2TESTNAS SSH Access](feedback_d2testnas_ssh.md) - Use root@192.168.0.9 with Paper123!@#, not sysadmin
|
||||
- [Bypass Permissions Setting](feedback_bypass_permissions_setting.md) - Set permissions.defaultMode to bypassPermissions in settings.json on all machines
|
||||
|
||||
## Machine
|
||||
- [Windows GURU-BEAST-ROG Setup](machine_windows_guru_setup_status.md) - Fully configured: Node.js, Ollama (qwen3:14b, nomic-embed-text), GrepAI, MCP servers. Pending: codestral:22b pull
|
||||
|
||||
## Project
|
||||
- [Audio Processor Architecture](project_audio_processor_architecture.md) - Segment-first pipeline: detect breaks before transcription for complete content capture
|
||||
- [Neptune Email Routing Issues](project_email_routing_neptune.md) - Multiple clients (devcon, Sorensen/rieussetcorp) have email not routing properly from Neptune
|
||||
- [Neptune SBR Email Routing Setup](project_neptune_sbr_email_routing.md) - Full SBR routing chain, config file locations, MailProtector integration, access methods
|
||||
- [Dataforth Test Datasheet Pipeline](project_datasheet_pipeline.md) - Full pipeline rebuilt 2026-03-27. Server-side generation replaces DFWDS/Uploader. Website upload still broken.
|
||||
- [Dataforth Security Incident](project_dataforth_incident_2026-03-27.md) - DF-JOEL2 compromised, MFA deployed, IC3 filed. CA policies enforce April 4.
|
||||
20
.claude/memory/feedback_bypass_permissions_setting.md
Normal file
20
.claude/memory/feedback_bypass_permissions_setting.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Bypass Permissions Persistent Setting
|
||||
description: Configure settings.json on all machines to persist bypass permissions mode across context compressions
|
||||
type: feedback
|
||||
---
|
||||
|
||||
Always set `permissions.defaultMode` to `"bypassPermissions"` in `~/.claude/settings.json` on all workstations.
|
||||
|
||||
**Why:** The `--dangerously-skip-permissions` CLI flag is not preserved when Claude Code compresses context or resumes sessions -- the new process starts without the flag, causing unexpected permission prompts mid-session. This is a known bug (GitHub issue #21974).
|
||||
|
||||
**How to apply:** On any new machine setup, ensure `~/.claude/settings.json` includes:
|
||||
```json
|
||||
{
|
||||
"permissions": {
|
||||
"defaultMode": "bypassPermissions"
|
||||
},
|
||||
"skipDangerousModePermissionPrompt": true
|
||||
}
|
||||
```
|
||||
This makes bypass mode the default without needing the CLI flag. Both keys are needed -- `defaultMode` sets the mode, `skipDangerousModePermissionPrompt` suppresses the warning dialog.
|
||||
11
.claude/memory/feedback_d2testnas_ssh.md
Normal file
11
.claude/memory/feedback_d2testnas_ssh.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: D2TESTNAS SSH Access
|
||||
description: D2TESTNAS SSH is root@192.168.0.9 with Paper123!@#, not sysadmin
|
||||
type: feedback
|
||||
---
|
||||
|
||||
D2TESTNAS SSH: use `root@192.168.0.9` with password `Paper123!@#`. The `sysadmin` user does not work for SSH. CachyOS workstation (acg-guru-5070) now has an ed25519 key authorized on D2TESTNAS for root.
|
||||
|
||||
**Why:** Credentials in credentials.md listed sysadmin as SSH user, which was incorrect and caused multiple failed attempts.
|
||||
|
||||
**How to apply:** When SSHing to D2TESTNAS, always use root@192.168.0.9. The SSH key at ~/.ssh/id_ed25519 (guru@acg-guru-5070) should work without password.
|
||||
44
.claude/memory/machine_windows_guru_setup_status.md
Normal file
44
.claude/memory/machine_windows_guru_setup_status.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: Windows GURU-BEAST-ROG Setup Status
|
||||
description: Windows workstation setup completion status - Ollama, GrepAI, MCP, Node.js all configured
|
||||
type: reference
|
||||
---
|
||||
|
||||
# Windows Machine Setup Status (GURU-BEAST-ROG)
|
||||
|
||||
**Created:** 2026-03-23
|
||||
**Updated:** 2026-03-24
|
||||
**Machine:** GURU-BEAST-ROG (Windows 11 Pro, i9-14900K, 128GB DDR5, RTX 4090)
|
||||
|
||||
## Software Status
|
||||
|
||||
| Software | Version | Path | Status |
|
||||
|----------|---------|------|--------|
|
||||
| Python | 3.12.10 | system PATH | [OK] |
|
||||
| Git | 2.52.0.windows.1 | system PATH | [OK] |
|
||||
| Windows OpenSSH | system | C:\Windows\System32\OpenSSH\ssh.exe | [OK] |
|
||||
| Node.js | v24.14.0 | C:\Program Files\nodejs | [OK] |
|
||||
| Ollama | v0.18.2 | C:\Users\guru\AppData\Local\Programs\Ollama\ollama.exe | [OK] |
|
||||
| GrepAI | v0.35.0 | C:\Users\guru\ClaudeTools\grepai.exe | [OK] |
|
||||
| credentials.md | -- | repo root | [OK] |
|
||||
|
||||
## Ollama Models
|
||||
|
||||
| Model | Size | Status |
|
||||
|-------|------|--------|
|
||||
| nomic-embed-text | 274 MB | [OK] |
|
||||
| qwen3:14b | 9.3 GB | [OK] |
|
||||
| codestral:22b | ~12 GB | [PENDING] - download interrupted, not pulled |
|
||||
|
||||
## Configuration
|
||||
|
||||
- **.mcp.json:** filesystem, sequential-thinking, grepai servers configured
|
||||
- **GrepAI:** Initialized, watcher configured, Ollama backend with nomic-embed-text
|
||||
- **Bypass permissions:** `permissions.defaultMode: "bypassPermissions"` in ~/.claude/settings.json
|
||||
- **In-repo memory:** .claude/memory/ (syncs via Gitea)
|
||||
|
||||
## Notes
|
||||
|
||||
- Ollama not in Git Bash PATH -- use full path or open new terminal
|
||||
- GrepAI watcher may need restart after reboot: `./grepai.exe watch --background`
|
||||
- Machine registered at `.claude/machines/guru-beast-rog.md`
|
||||
32
.claude/memory/project_audio_processor_architecture.md
Normal file
32
.claude/memory/project_audio_processor_architecture.md
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Audio Processor - Segment-First Architecture
|
||||
description: Revised pipeline architecture - detect breaks and split into segments BEFORE transcription for complete content capture
|
||||
type: project
|
||||
---
|
||||
|
||||
## Revised Pipeline Architecture (decided 2026-03-22)
|
||||
|
||||
Shows are almost always 4 segments per hour (8 total for a 2-hour show). Extra breaks are rare.
|
||||
|
||||
**Old approach:** Transcribe full episode -> truncate to fit LLM context -> analyze (loses content)
|
||||
|
||||
**New approach:** Detect breaks first (audio-only) -> split into ~8 segments -> transcribe each -> analyze each with full context -> cross-segment synthesis
|
||||
|
||||
### Pipeline Order
|
||||
|
||||
1. **Audio-level break detection** (no transcript needed) — loudness/compression jumps, silence gaps, known bumper fingerprints, HR1/HR2 boundary
|
||||
2. **Split into segments** — ~7-15 min each, complete audio chunks
|
||||
3. **Transcribe each segment** — smaller files, complete content, no truncation
|
||||
4. **Analyze each segment** — full transcript fits in LLM context window easily
|
||||
5. **Cross-segment synthesis** — detect topics spanning segments, callbacks ("going back to what we said before the break"), narrative arc
|
||||
6. **Generate content** — blog posts, forum posts, episode summary from complete analysis
|
||||
|
||||
### Key Insights
|
||||
|
||||
- 4 segments/hour is a strong structural prior for break detection — if 12-18 min into a segment and audio signatures appear, almost certainly a break. At 5 min, probably not.
|
||||
- Each segment transcript is ~5-10K chars — fits in any LLM context with room for detailed prompts
|
||||
- Cross-segment synthesis pass is new and essential for catching callbacks and recurring topics
|
||||
|
||||
**Why:** Solves the context window truncation problem that loses show content. Each segment gets complete analysis.
|
||||
|
||||
**How to apply:** This is the architecture direction for all future audio processor work. The existing Stage 3 segment detector needs to work without transcript input (audio-only signals). Stage 6 analyzer needs per-segment + synthesis passes.
|
||||
37
.claude/memory/project_dataforth_incident_2026-03-27.md
Normal file
37
.claude/memory/project_dataforth_incident_2026-03-27.md
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
name: Dataforth Security Incident 2026-03-27
|
||||
description: DF-JOEL2 compromised via ScreenConnect social engineering. MFA deployed. IC3 filed. C2 IPs blocked. Full remediation completed.
|
||||
type: project
|
||||
---
|
||||
|
||||
## Incident
|
||||
Joel Lohr's workstation (DF-JOEL2, 192.168.0.143) compromised via phishing email to personal Yahoo account. Attacker "Angel Raya" deployed ScreenConnect C2 backdoors. M365 account also compromised from Turkey/UK/Germany.
|
||||
|
||||
## Attacker
|
||||
- C2: 80.76.49.18 and 45.88.91.99 (AS399486, Virtuo, Montreal QC) - SUSPENDED by host
|
||||
- Cloud relay: instance-wlb9ga-relay.screenconnect.com
|
||||
- ConnectWise case: 03464184
|
||||
- IC3 complaint: 1c32ade367084be9acd548f23705736f
|
||||
|
||||
## Remediation
|
||||
- C2 IPs blocked at UDM firewall (iptables - need permanent rules in UniFi UI)
|
||||
- 3 rogue ScreenConnect clients uninstalled
|
||||
- jlohr AD password reset, M365 sessions revoked
|
||||
- 32 machines scanned clean, 28 unreachable (offline)
|
||||
- No lateral movement detected
|
||||
|
||||
## MFA Rollout
|
||||
- 3 CA policies deployed (report-only until April 4, 2026):
|
||||
- Require MFA (skip from office IP 67.206.163.122)
|
||||
- Block foreign sign-ins (US only, MFA-Travel-Bypass group for exceptions)
|
||||
- Block legacy auth
|
||||
- 19/38 users MFA-ready, 19 need to register
|
||||
- MFA notice sent to all users, deadline April 4
|
||||
|
||||
## Joel Lohr
|
||||
- Retiring March 31, 2026
|
||||
- Auto-reply directs contacts to Dan Center (dcenter@dataforth.com)
|
||||
- Account should be disabled after retirement
|
||||
|
||||
**Why:** Active security incident requiring immediate response.
|
||||
**How to apply:** Monitor CA policies in report-only mode, enforce April 4. Check 28 offline machines when available. Add C2 IPs to permanent UDM block list.
|
||||
73
.claude/memory/project_datasheet_pipeline.md
Normal file
73
.claude/memory/project_datasheet_pipeline.md
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: Dataforth Test Datasheet Pipeline - Rebuilt 2026-03-27
|
||||
description: Full pipeline from DOS test stations to website. New server-side generation replaces DFWDS/Uploader. 72/73 Quatronix datasheets generated. AD2 crypto wipe recovery.
|
||||
type: project
|
||||
---
|
||||
|
||||
## Background
|
||||
AD2 (192.168.0.6) was wiped in a crypto/ransomware attack months ago. The test datasheet pipeline was broken. Customer Quatronix (China) blocking shipment of 328 modules (whittled to 54) without datasheets.
|
||||
|
||||
## Pipeline (5 stages, rebuilt 2026-03-27)
|
||||
|
||||
### Stage 1: DOS Test Stations (64 stations)
|
||||
- QuickBASIC programs generate test data -> C:\STAGE on each DOS PC
|
||||
- DAT files (raw test data) + TXT files (formatted datasheets)
|
||||
- CTONW.BAT copies DAT files to NAS (working)
|
||||
- CTONWTXT.BAT copies TXT files (NOT called in current AUTOEXEC v4.1 since 2026-03-12)
|
||||
- TXT files piling up in C:\STAGE since Sept 2025
|
||||
|
||||
### Stage 2: NAS <-> AD2 Sync
|
||||
- Script: C:\Shares\test\scripts\Sync-FromNAS-rsync.ps1 (every 15 min, WORKING)
|
||||
- Rsync daemon on NAS: port 873, module "test", user rsync / IQ203s32119
|
||||
- PULL: DAT files from NAS -> AD2, triggers database import
|
||||
- PUSH: Software updates from AD2 -> NAS for DOS machines
|
||||
|
||||
### Stage 3: TestDataDB (Node.js/SQLite, WORKING)
|
||||
- App: C:\Shares\testdatadb\ (Windows service "testdatadb", auto-start)
|
||||
- API: http://192.168.0.6:3000
|
||||
- Database: C:\Shares\testdatadb\database\testdata.db (2.27M records)
|
||||
- Import: database/import.js (post-import hook calls export)
|
||||
- **NEW: Spec parser** (parsers/spec-reader.js) - reads binary spec DATs, 1470 models
|
||||
- **NEW: Exact-match formatter** (templates/datasheet-exact.js) - reverse-engineered from QB
|
||||
- **NEW: Auto-export** (database/export-datasheets.js) - generates TXT to X:\For_Web
|
||||
|
||||
### Stage 4: WebShare (X: = \\ad2\webshare = C:\Shares\webshare)
|
||||
- X:\Test_Datasheets - incoming (staging for old DFWDS)
|
||||
- X:\For_Web - validated datasheets (501K+ files, pre-2026 archived to year subfolders)
|
||||
- X:\For_Web_PDF - PDF versions (4.7K files)
|
||||
- X:\Bad_Datasheets - invalid files (18K)
|
||||
- X:\Datasheets_Log - DFWDS logs
|
||||
|
||||
### Stage 5: Website Upload (BROKEN)
|
||||
- Old endpoints: dataforth.com/Services/{Uploader,DirectoryManifest,DeleteFile}.aspx - ALL 404
|
||||
- Credentials: DataforthWebShare / Data6277
|
||||
- TestDataSheetUploader (VB.NET, Hoffman) - not running, config pointed to dev paths
|
||||
- Legacy site: legacy.dataforth.com/TestDataReport_Print.aspx (still works, no auth)
|
||||
- New site: dataforth.com/TestDataReport (requires OIDC login)
|
||||
|
||||
## What Was Eliminated by Rebuild
|
||||
- CTONWTXT.BAT (DOS TXT transfer) - no longer needed, server generates from DAT data
|
||||
- DFWDS.exe (VB6 filename decoder) - no longer needed
|
||||
- TestDataSheetUploader (VB.NET web uploader) - endpoints dead anyway
|
||||
|
||||
## Key File Encoding
|
||||
H-prefix decode: A=10, B=11, C=12, D=13, E=14, F=15, G=16, H=17, I=18, J=19
|
||||
Example: H8601-6.TXT -> serial 178601-6
|
||||
New pipeline extracts SN from DAT record data directly, not filenames.
|
||||
|
||||
## Open Items
|
||||
1. Website upload replacement (old ASP.NET endpoints dead)
|
||||
2. 7B datasheet formatting (specs loaded, needs 7B-specific layout, ~830K records)
|
||||
3. SCM5B49 spec file empty - need from John Lehman
|
||||
4. Service permissions (runs as SYSTEM, causes SHM/WAL conflicts)
|
||||
5. New product lines: MAQ20/PWRM (XLS), 10D (JSON, ~May 2026), DSCMHV
|
||||
|
||||
## Key Contacts
|
||||
- John Lehman (jlehman@dataforth.com) - Engineering, QB code, specs
|
||||
- Peter Iliya (pIliya@dataforth.com) - Applications Engineer, manual datasheet retrieval
|
||||
- Ken Hoffman - TestDataSheetUploader author (VB.NET), DFWDS author, unresponsive
|
||||
- Georg Haubner (ghaubner@dataforth.com) - D: drive has pre-crypto backup of network shares
|
||||
- Ginger (gy@quatronix-cn.com) - Quatronix China, customer requesting datasheets
|
||||
|
||||
**Why:** Critical business issue - customer refusing shipments without datasheets.
|
||||
**How to apply:** Pipeline is mostly rebuilt. Priority: website upload replacement, then 7B support.
|
||||
11
.claude/memory/project_email_routing_neptune.md
Normal file
11
.claude/memory/project_email_routing_neptune.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Neptune Email Routing Issues
|
||||
description: Multiple clients (devcon, Sorensen/rieussetcorp) have email not routing properly from Neptune
|
||||
type: project
|
||||
---
|
||||
|
||||
Sorensen (rieussetcorp) and devcon both have the same email routing issue from Neptune — emails not routing properly.
|
||||
|
||||
**Why:** Recurring issue affecting multiple clients, likely a shared configuration or Neptune platform problem rather than isolated incidents.
|
||||
|
||||
**How to apply:** When troubleshooting email routing for any client on Neptune, check if the fix applied to one client needs to be replicated for others. Track as a systemic Neptune issue, not individual client problems.
|
||||
49
.claude/memory/project_neptune_sbr_email_routing.md
Normal file
49
.claude/memory/project_neptune_sbr_email_routing.md
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: Neptune SBR Email Routing Setup
|
||||
description: How outbound email routing works on Neptune Exchange - SBR agent, MailProtector smarthost, send connectors, and common fix for new clients
|
||||
type: project
|
||||
---
|
||||
|
||||
## Neptune Outbound Email Routing Chain
|
||||
|
||||
1. User sends mail from Exchange mailbox on Neptune (172.16.3.11)
|
||||
2. **Microsoft.Exchange.SBR** transport agent (Priority 12) fires on OnResolved event
|
||||
3. SBR reads config files at `C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\agents\Custom\`:
|
||||
- `Microsoft.Exchange.SBR.InternalDomains.config` — list of domains SBR handles
|
||||
- `Microsoft.Exchange.SBR.OverrideSettings.config` — maps `domain.com;domain.sbr` for routing
|
||||
- `Microsoft.Exchange.SBR.IgnoreAuthAs.config` — exclusions
|
||||
4. SBR rewrites recipient routing to `.sbr` domain (e.g., `rieussetcorp.sbr`)
|
||||
5. Exchange matches `.sbr` address space to the corresponding Send Connector (e.g., `Outbound.Sorensen`)
|
||||
6. Send connector smarthosts through MailProtector: `domain-com.outbound.emailservice.io`
|
||||
7. MailProtector relays to final destination
|
||||
|
||||
There is also a **messageconcept ExSBR** agent at Priority 11 (`C:\Program Files\messageconcept\ExSBR\`).
|
||||
|
||||
## Common Issue: New client or server move
|
||||
|
||||
When Neptune's IP changes or a new domain is added, MailProtector must have the sending server IP authorized. Without this, MailProtector accepts the relay but drops/rejects the message.
|
||||
|
||||
**Fix (2026-03-22 for rieussetcorp.com):** Added 67.206.163.124 and 67.206.163.122 to MailProtector's authorized sender IPs.
|
||||
|
||||
## Neptune Location
|
||||
|
||||
Neptune physically moved from ACG office (72.194.62.7) to Dataforth (67.206.163.124 inbound, 67.206.163.122 outbound). SNAT rule on Dataforth UDM (`/data/on_boot.d/10-neptune-snat.sh`) should force outbound to use .124.
|
||||
|
||||
## Access
|
||||
|
||||
- WinRM: `172.16.3.11`, ACG\administrator, via pywinrm with NTLM
|
||||
- Exchange PS: Connect via `New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://neptune.acg.local/PowerShell/ -Authentication Kerberos`
|
||||
- Requires Tailscale route through D2TESTNAS (192.168.0.9) for 172.16.0.0/22
|
||||
|
||||
## Known Issues (as of 2026-03-22)
|
||||
|
||||
- 67.206.163.122 has no PTR record and is blacklisted by some providers
|
||||
- SNAT rule may not be active — outbound was going as .122 not .124 on 3/16. Need to check UDM (192.168.0.254) — couldn't auth via SSH tonight, check in morning
|
||||
- MAIL transport server still exists in Exchange config but server is decommissioned
|
||||
- Spam queues with junk domains (wwwyamaha666.ru, bestspatulas.com, etc.)
|
||||
- Tailscale 172.16.0.0/22 route moved from ACG pfSense to D2TESTNAS — may need permanent solution
|
||||
- UDM SSH password (Paper123!@#-unifi) was rejected — may have changed
|
||||
|
||||
## Resolved (2026-03-22)
|
||||
|
||||
- rieussetcorp.com outbound: Added 67.206.163.124 and .122 to MailProtector authorized IPs — mail now flowing
|
||||
48
.claude/memory/reference_community_forum.md
Normal file
48
.claude/memory/reference_community_forum.md
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: Community Forum (Flarum)
|
||||
description: Flarum forum at community.azcomputerguru.com - platform details, API access, database credentials, and posting workflow
|
||||
type: reference
|
||||
---
|
||||
|
||||
## Community Forum - Flarum
|
||||
|
||||
- **URL:** https://community.azcomputerguru.com
|
||||
- **Platform:** Flarum 1.8.14
|
||||
- **Server:** IX server (172.16.3.10), cPanel account `azcomputerguru`
|
||||
- **Document Root:** `/home/azcomputerguru/public_html/community/public`
|
||||
- **PHP Version:** 8.1.33
|
||||
|
||||
### Database
|
||||
- **Host:** localhost (on IX server)
|
||||
- **Database:** `azcompu_flarum`
|
||||
- **User:** `azcompu_flarum`
|
||||
- **Password:** `Fl@rum2026!CGS`
|
||||
|
||||
### API
|
||||
- **API Key:** `581b6c8c162a383ba87757f41b4381e9bf8db61d71bd578ee97fe32b7aeac046` (admin user, ID 1)
|
||||
- **API Base:** `https://community.azcomputerguru.com/api`
|
||||
- **Note:** Cloudflare blocks external API access. Must either:
|
||||
1. Use `--resolve` with `curl -k` from IX server localhost
|
||||
2. Use direct PHP/database script on IX server (preferred, more reliable)
|
||||
|
||||
### Forum Tags (Categories)
|
||||
| ID | Name | Slug |
|
||||
|----|------|------|
|
||||
| 1 | General | general |
|
||||
| 2 | Tech News | tech-news |
|
||||
| 3 | Security & Privacy | security-privacy |
|
||||
| 4 | Artificial Intelligence | artificial-intelligence |
|
||||
| 5 | Space Tech | space-tech |
|
||||
| 6 | Gadgets & Hardware | gadgets-hardware |
|
||||
| 7 | How-Tos & Tips | how-tos-tips |
|
||||
| 8 | Show Discussion | show-discussion |
|
||||
| 9 | Off-Topic | off-topic |
|
||||
|
||||
### Posting Workflow
|
||||
Cloudflare blocks the Flarum REST API from external requests. To create posts programmatically:
|
||||
1. Write a PHP script that inserts directly into the database (discussions + posts + discussion_tag tables)
|
||||
2. SCP the script and JSON payload to IX server `/tmp/`
|
||||
3. Execute via `php /tmp/script.php` over SSH
|
||||
4. Clean up temp files
|
||||
|
||||
**How to apply:** Use this when the user asks to create forum posts or manage the community forum.
|
||||
7
.claude/memory/reference_dataforth_contact.md
Normal file
7
.claude/memory/reference_dataforth_contact.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Dataforth Contact - AJ
|
||||
description: AJ at Dataforth - email forwarding setup needed for dataforthgit@ address
|
||||
type: reference
|
||||
---
|
||||
|
||||
AJ at Dataforth needs messages sent to the dataforthgit@ email address to forward to him.
|
||||
7
.claude/memory/reference_ix_access_tailscale.md
Normal file
7
.claude/memory/reference_ix_access_tailscale.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: IX Server Access via Tailscale
|
||||
description: IX server (ix.azcomputerguru.com) is accessible with Tailscale on, no VPN needed
|
||||
type: reference
|
||||
---
|
||||
|
||||
IX server (ix.azcomputerguru.com / 172.16.3.10) can be accessed directly when Tailscale is on. No separate VPN connection required.
|
||||
18
.claude/memory/reference_ix_server_ssh.md
Normal file
18
.claude/memory/reference_ix_server_ssh.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: IX Server SSH Access
|
||||
description: SSH access notes for IX server - key auth not set up on CachyOS workstation, must use sshpass with password
|
||||
type: reference
|
||||
---
|
||||
|
||||
## IX Server SSH from CachyOS Workstation
|
||||
|
||||
- **Host:** 172.16.3.10 (ix.azcomputerguru.com)
|
||||
- **User:** root
|
||||
- **Password:** See credentials.md
|
||||
- **SSH Key Auth:** NOT configured on CachyOS workstation (acg-guru-5070)
|
||||
- **Must use:** `sshpass -p 'PASSWORD' ssh -o StrictHostKeyChecking=no -o PubkeyAuthentication=no root@172.16.3.10`
|
||||
- **Suppress warnings:** Pipe through `grep -v WARNING | grep -v 'not using'` or `tail`
|
||||
|
||||
**Why:** The SSH key from this machine hasn't been added to IX server's authorized_keys yet. The old WSL key (guru@wsl) was authorized but this is a new CachyOS install.
|
||||
|
||||
**How to apply:** When running commands on IX server, use sshpass approach. Consider setting up SSH key auth to simplify future access.
|
||||
40
.claude/memory/reference_matomo_analytics.md
Normal file
40
.claude/memory/reference_matomo_analytics.md
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: Matomo Analytics
|
||||
description: Self-hosted Matomo analytics at analytics.azcomputerguru.com - credentials, site IDs, tracking setup for all 3 sites
|
||||
type: reference
|
||||
---
|
||||
|
||||
## Matomo Analytics
|
||||
|
||||
- **URL:** https://analytics.azcomputerguru.com
|
||||
- **Platform:** Matomo 5.8.0 (PHP)
|
||||
- **Server:** IX server (172.16.3.10), cPanel account `azcomputerguru`
|
||||
- **Document Root:** `/home/azcomputerguru/public_html/analytics/`
|
||||
|
||||
### Login
|
||||
- **User:** MikeSwanson
|
||||
- **Password:** Mat0mo2026!CGS
|
||||
- **Email:** mike@azcomputerguru.com
|
||||
|
||||
### Database
|
||||
- **Host:** localhost (on IX server)
|
||||
- **Database:** `azcompu_matomo`
|
||||
- **User:** `azcompu_matomo`
|
||||
- **Password:** `Mat0mo2026!CGS`
|
||||
|
||||
### Tracked Sites
|
||||
| Site ID | Name | URL | Tracking Method |
|
||||
|---------|------|-----|-----------------|
|
||||
| 1 | AZ Computer Guru | https://azcomputerguru.com | WordPress mu-plugin (`wp-content/mu-plugins/matomo-tracking.php`) |
|
||||
| 2 | Community Forum | https://community.azcomputerguru.com | Flarum `custom_header` DB setting |
|
||||
| 3 | Radio Show | https://radio.azcomputerguru.com | Injected into HTML files before `</head>` |
|
||||
|
||||
### Cron
|
||||
- Archiving cron runs every 5 minutes as `azcomputerguru` user
|
||||
- Command: `php /home/azcomputerguru/public_html/analytics/console core:archive`
|
||||
|
||||
### Cloudflare
|
||||
- DNS record points to 72.194.62.5, proxied (orange cloud)
|
||||
- Was previously pointing to wrong IP (52.52.94.202), fixed 2026-03-20
|
||||
|
||||
**How to apply:** Use this when managing analytics, adding new sites to track, or troubleshooting tracking code.
|
||||
7
.claude/memory/reference_neptune_access_d2testnas.md
Normal file
7
.claude/memory/reference_neptune_access_d2testnas.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Neptune Access via D2TESTNAS
|
||||
description: Neptune Exchange server must be accessed by routing through D2TESTNAS (not direct VPN)
|
||||
type: reference
|
||||
---
|
||||
|
||||
Neptune (neptune.acghosting.com / 172.16.3.11) must be accessed by routing through D2TESTNAS, not via direct VPN connection.
|
||||
23
.claude/memory/reference_radio_website.md
Normal file
23
.claude/memory/reference_radio_website.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Radio Show Website
|
||||
description: The Computer Guru Show website at radio.azcomputerguru.com - Astro static site on IX server cPanel
|
||||
type: reference
|
||||
---
|
||||
|
||||
## Radio Show Website
|
||||
|
||||
- **URL:** https://radio.azcomputerguru.com
|
||||
- **Platform:** Astro 6.0.4 (static site generator)
|
||||
- **Server:** IX server (172.16.3.10), cPanel account `azcomputerguru`
|
||||
- **Document Root:** `/home/azcomputerguru/public_html/radio`
|
||||
- **Source Code:** `projects/radio-show/website/` in ClaudeTools repo
|
||||
- **Build:** `cd projects/radio-show/website && npm run build` produces `dist/` folder
|
||||
- **Deploy:** rsync/SCP `dist/` contents to document root on IX server
|
||||
|
||||
### Community Link
|
||||
- The community page (`/community`) links to:
|
||||
- Discord server (placeholder, WidgetBot)
|
||||
- Flarum forum at https://community.azcomputerguru.com
|
||||
- Newsletter signup (placeholder)
|
||||
|
||||
**How to apply:** Use when deploying website updates or managing the radio show project.
|
||||
35
.claude/memory/reference_workstation_setup.md
Normal file
35
.claude/memory/reference_workstation_setup.md
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: CachyOS Workstation Setup
|
||||
description: Current workstation config - CachyOS on ASUS laptop, dual NVMe, autostart apps, old home btrfs subvolume location
|
||||
type: reference
|
||||
---
|
||||
|
||||
## Workstation: acg-guru-5070
|
||||
|
||||
- **OS:** CachyOS (Arch-based), kernel 6.19.x
|
||||
- **DE:** KDE Plasma 6 (Wayland)
|
||||
- **CPU/GPU:** Intel Arrow Lake-S + NVIDIA RTX 5070 Ti Mobile
|
||||
- **Tailscale IP:** 100.95.216.79
|
||||
|
||||
### Storage
|
||||
- **nvme0n1:** 954GB btrfs - CachyOS install (OS, root)
|
||||
- **nvme1n1:** 954GB ext4 - `/home` (formatted from old Windows drive)
|
||||
- **Old home:** btrfs `@home` subvolume on nvme0n1, mount with: `sudo mount -o subvol=@home UUID=8a8b1d34-99fb-470f-82ca-b5d08e43ec32 /mnt/old-home`
|
||||
|
||||
### Autostart Apps (~/.config/autostart/)
|
||||
- `arch-update-tray.desktop` (pre-existing)
|
||||
- `cachyos-hello.desktop` (pre-existing)
|
||||
- `discord.desktop` (added, starts minimized)
|
||||
- `tailscale-systray.desktop` (added)
|
||||
- ScreenConnect: autostart removed (on-demand only via URI scheme handler from web UI)
|
||||
|
||||
### Known Issues
|
||||
- **Warm reboot hangs:** Rebooting (e.g. for GPU issues) causes system to hang with spinning symbol — requires hard power-off. Observed multiple times. Likely NVIDIA driver not unloading cleanly during shutdown.
|
||||
|
||||
### Key Fixes Applied
|
||||
- **Tailscale:** `--accept-routes`, systemd-resolved + NetworkManager DNS config
|
||||
- **Brightness:** Hide nvidia_0 backlight via udev rule, KDE controls intel_backlight only
|
||||
- **ScreenConnect:** dpkg + full JRE + Wayland patch (GDK_BACKEND=x11)
|
||||
- **Sudo:** NOPASSWD for guru user
|
||||
|
||||
**How to apply:** Reference when troubleshooting workstation issues or setting up additional services.
|
||||
222
.claude/skills/1password/references/integrations.md
Normal file
222
.claude/skills/1password/references/integrations.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# 1Password Integration Patterns
|
||||
|
||||
Common patterns for integrating 1Password with developer tools and AI workflows.
|
||||
|
||||
## Claude Code / Claude Desktop
|
||||
|
||||
### Claude Desktop MCP Config
|
||||
|
||||
Store API keys securely and reference them in `claude_desktop_config.json`:
|
||||
|
||||
```bash
|
||||
# Store the key
|
||||
op item create --category API_CREDENTIAL --title "My MCP Server" \
|
||||
--vault Dev api_key[password]=your-key-here
|
||||
|
||||
# Get the secret reference
|
||||
# op://Dev/My MCP Server/api_key
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-server": {
|
||||
"command": "op",
|
||||
"args": ["run", "--", "node", "/path/to/server.js"],
|
||||
"env": {
|
||||
"API_KEY": "op://Dev/My MCP Server/api_key"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Claude Code Shell Environment
|
||||
|
||||
```bash
|
||||
# .env.tpl (safe to commit — no real secrets)
|
||||
ANTHROPIC_API_KEY=op://Dev/Anthropic/api_key
|
||||
OPENAI_API_KEY=op://Dev/OpenAI/api_key
|
||||
|
||||
# ✅ Wrap claude with op run — secrets injected into subprocess only
|
||||
op run --env-file=.env.tpl -- claude
|
||||
|
||||
# ✅ Or export individually for interactive shell use
|
||||
export ANTHROPIC_API_KEY=$(op read "op://Dev/Anthropic/api_key")
|
||||
claude
|
||||
```
|
||||
|
||||
### In CLAUDE.md (project secrets reference)
|
||||
|
||||
```markdown
|
||||
## Secrets Setup
|
||||
Secrets are managed via 1Password. Run before working:
|
||||
```bash
|
||||
op run --env-file=.env.tpl -- claude
|
||||
```
|
||||
Do NOT commit `.env` — commit `.env.tpl` only.
|
||||
```
|
||||
|
||||
## n8n
|
||||
|
||||
### Environment Injection at Startup
|
||||
|
||||
```bash
|
||||
# n8n.env.tpl (commit this)
|
||||
N8N_ENCRYPTION_KEY=op://Dev/n8n/encryption_key
|
||||
DB_POSTGRESDB_PASSWORD=op://Dev/n8n-postgres/password
|
||||
N8N_BASIC_AUTH_PASSWORD=op://Dev/n8n/basic_auth_password
|
||||
|
||||
# docker-compose.yml startup
|
||||
op run --env-file=n8n.env.tpl -- docker compose up -d n8n
|
||||
```
|
||||
|
||||
### n8n Credential Storage via API
|
||||
|
||||
Use n8n's credential API to push secrets from 1Password into n8n:
|
||||
|
||||
```bash
|
||||
# Get secret from 1Password
|
||||
API_KEY=$(op read "op://Dev/Some Service/api_key")
|
||||
|
||||
# Push to n8n credential (HTTP Request)
|
||||
curl -s -X POST "https://n8n.example.com/api/v1/credentials" \
|
||||
-H "X-N8N-API-KEY: $(op read 'op://Dev/n8n/api_key')" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"name\": \"Service Credential\", \"type\": \"httpHeaderAuth\", \"data\": {\"name\": \"Authorization\", \"value\": \"Bearer $API_KEY\"}}"
|
||||
```
|
||||
|
||||
## Docker / Docker Compose
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
app:
|
||||
image: myapp:latest
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL}
|
||||
API_KEY: ${API_KEY}
|
||||
```
|
||||
|
||||
```bash
|
||||
# .env.tpl
|
||||
DATABASE_URL=op://Dev/Postgres/connection_string
|
||||
API_KEY=op://Dev/MyApp/api_key
|
||||
|
||||
# Start with injection
|
||||
op run --env-file=.env.tpl -- docker compose up
|
||||
```
|
||||
|
||||
## Python Scripts
|
||||
|
||||
```python
|
||||
import subprocess
|
||||
|
||||
def get_secret(reference: str) -> str:
|
||||
"""Read a secret from 1Password using a secret reference."""
|
||||
result = subprocess.run(
|
||||
["op", "read", reference],
|
||||
capture_output=True, text=True, check=True
|
||||
)
|
||||
return result.stdout.strip()
|
||||
|
||||
# Usage
|
||||
api_key = get_secret("op://Dev/Anthropic/api_key")
|
||||
```
|
||||
|
||||
Or using the 1Password Python SDK (if available):
|
||||
```bash
|
||||
pip install onepassword-sdk
|
||||
```
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import onepassword
|
||||
|
||||
async def main():
|
||||
client = await onepassword.Client.authenticate(
|
||||
auth=os.environ["OP_SERVICE_ACCOUNT_TOKEN"],
|
||||
integration_name="My Script",
|
||||
integration_version="1.0.0",
|
||||
)
|
||||
secret = await client.secrets.resolve("op://Dev/Anthropic/api_key")
|
||||
```
|
||||
|
||||
## GitHub Actions / CI
|
||||
|
||||
```yaml
|
||||
# .github/workflows/deploy.yml
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: 1password/load-secrets-action@v2
|
||||
with:
|
||||
export-env: true
|
||||
env:
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
|
||||
ANTHROPIC_API_KEY: op://Dev/Anthropic/api_key
|
||||
DEPLOY_KEY: op://Dev/Deploy/private_key
|
||||
|
||||
- run: deploy-script.sh # ANTHROPIC_API_KEY is available
|
||||
```
|
||||
|
||||
## Shell / .zshrc Auto-Load
|
||||
|
||||
```bash
|
||||
# ~/.zshrc
|
||||
# Auto-load common dev secrets on shell start (optional — only if you trust your machine)
|
||||
load_dev_secrets() {
|
||||
if command -v op &>/dev/null && op whoami &>/dev/null 2>&1; then
|
||||
source <(op run --env-file=~/.config/dev.env.tpl -- env 2>/dev/null) && \
|
||||
echo "✅ Dev secrets loaded from 1Password"
|
||||
fi
|
||||
}
|
||||
|
||||
# Call explicitly when needed:
|
||||
alias load-secrets='load_dev_secrets'
|
||||
```
|
||||
|
||||
## Supabase
|
||||
|
||||
```bash
|
||||
# Store Supabase credentials
|
||||
op item create --category API_CREDENTIAL --title "Supabase - My Project" \
|
||||
--vault Dev \
|
||||
url[text]=https://myproject.supabase.co \
|
||||
anon_key[password]=eyJ... \
|
||||
service_key[password]=eyJ...
|
||||
|
||||
# Use in scripts
|
||||
SUPABASE_URL=$(op read "op://Dev/Supabase - My Project/url")
|
||||
SUPABASE_KEY=$(op read "op://Dev/Supabase - My Project/service_key")
|
||||
```
|
||||
|
||||
## Replit
|
||||
|
||||
Replit has its own Secrets manager, but for local dev before deploying:
|
||||
|
||||
```bash
|
||||
# Generate a .env from 1Password, then paste values into Replit Secrets UI
|
||||
op run --env-file=.env.tpl -- env | grep -E "^(ANTHROPIC|SUPABASE|N8N)"
|
||||
# Copy output values → paste into Replit Secrets one by one
|
||||
```
|
||||
|
||||
## Rotation Workflow
|
||||
|
||||
When rotating a credential:
|
||||
|
||||
```bash
|
||||
# 1. Update in the service (get new key)
|
||||
NEW_KEY="new-key-from-service"
|
||||
|
||||
# 2. Update in 1Password
|
||||
op item edit "Service Name" api_key[password]="$NEW_KEY"
|
||||
|
||||
# 3. Verify
|
||||
op read "op://Dev/Service Name/api_key"
|
||||
|
||||
# 4. Re-inject wherever used
|
||||
source <(op run --env-file=.env.tpl -- env)
|
||||
# Or restart services that use the key
|
||||
```
|
||||
171
.claude/skills/1password/references/op_commands.md
Normal file
171
.claude/skills/1password/references/op_commands.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# 1Password CLI (op) Command Reference
|
||||
|
||||
## Authentication
|
||||
|
||||
```bash
|
||||
# Sign in (interactive)
|
||||
op signin
|
||||
|
||||
# Sign in to specific account
|
||||
op signin --account team-name.1password.com
|
||||
|
||||
# Check who you're signed in as
|
||||
op whoami
|
||||
|
||||
# List accounts
|
||||
op account list
|
||||
|
||||
# Service account (CI/CD — set env var, no signin needed)
|
||||
export OP_SERVICE_ACCOUNT_TOKEN="your-token"
|
||||
```
|
||||
|
||||
## Items
|
||||
|
||||
```bash
|
||||
# List items
|
||||
op item list
|
||||
op item list --vault Dev
|
||||
op item list --categories API_CREDENTIAL
|
||||
|
||||
# Get item details
|
||||
op item get "Item Title"
|
||||
op item get "Item Title" --vault Dev
|
||||
op item get "Item Title" --format json
|
||||
|
||||
# Get a specific field
|
||||
op item get "Item Title" --fields api_key
|
||||
op item get "Item Title" --fields label=api_key
|
||||
|
||||
# Read using secret reference (most common)
|
||||
op read "op://Dev/Item Title/api_key"
|
||||
|
||||
# Create item
|
||||
op item create --category API_CREDENTIAL --title "My API Key" api_key[password]=sk-abc123
|
||||
op item create --category LOGIN --title "Service Account" --vault Dev \
|
||||
username[text]=myuser password[password]=mypass
|
||||
|
||||
# Edit/update item
|
||||
op item edit "Item Title" api_key[password]=new-value
|
||||
op item edit "Item Title" --vault Dev new_field[text]=value
|
||||
|
||||
# Delete item
|
||||
op item delete "Item Title"
|
||||
op item delete "Item Title" --vault Dev
|
||||
|
||||
# Move item to different vault
|
||||
op item move "Item Title" --current-vault Dev --destination-vault Personal
|
||||
```
|
||||
|
||||
## Vaults
|
||||
|
||||
```bash
|
||||
# List vaults
|
||||
op vault list
|
||||
op vault list --format json
|
||||
|
||||
# Create vault
|
||||
op vault create "New Vault"
|
||||
|
||||
# Get vault details
|
||||
op vault get "Vault Name"
|
||||
```
|
||||
|
||||
## Secrets Injection
|
||||
|
||||
```bash
|
||||
# Run command with secrets from .env template (RECOMMENDED)
|
||||
op run --env-file=.env.tpl -- your-command arg1 arg2
|
||||
|
||||
# Inject into Docker
|
||||
op run --env-file=.env.tpl -- docker compose up
|
||||
|
||||
# Inject a single reference via env var (op run picks up op:// values automatically)
|
||||
export API_KEY="op://Dev/MyApp/api_key"
|
||||
op run -- node app.js # API_KEY is resolved at runtime
|
||||
|
||||
# ⚠️ AVOID: sourcing op run output into the current shell
|
||||
# source <(op run --env-file=.env.tpl -- env) ← UNSAFE
|
||||
# If secret values contain $(...) or backticks, they execute as shell code.
|
||||
# Use 'op run -- your-command' instead (secrets stay in subprocess only).
|
||||
```
|
||||
|
||||
## Password Generation
|
||||
|
||||
```bash
|
||||
# Generate at item creation time (no standalone command)
|
||||
op item create --category PASSWORD --title "Generated Secret" \
|
||||
--generate-password='letters,digits,symbols,32'
|
||||
|
||||
# Generate with custom recipe
|
||||
op item create --category LOGIN --title "My Login" \
|
||||
--generate-password='letters,digits,20'
|
||||
|
||||
# Or use openssl for scripted generation
|
||||
openssl rand -base64 32 | tr -d '=+/'
|
||||
```
|
||||
|
||||
## Document / File Management
|
||||
|
||||
```bash
|
||||
# Store a file
|
||||
op document create ./private-key.pem --title "SSH Private Key" --vault Dev
|
||||
|
||||
# Get a file
|
||||
op document get "SSH Private Key" --output ./private-key.pem
|
||||
|
||||
# List documents
|
||||
op document list
|
||||
```
|
||||
|
||||
## Service Accounts (CI/CD)
|
||||
|
||||
```bash
|
||||
# Create service account (in 1Password UI: Settings → Developer → Service Accounts)
|
||||
# Then set token as env var:
|
||||
export OP_SERVICE_ACCOUNT_TOKEN="ops_eyJ..."
|
||||
|
||||
# No signin needed — op commands work automatically
|
||||
op item list # works with service account token
|
||||
op read "op://vault/item/field"
|
||||
```
|
||||
|
||||
## Connect (Self-hosted, advanced)
|
||||
|
||||
```bash
|
||||
# For teams running 1Password Connect server
|
||||
export OP_CONNECT_HOST="https://your-connect-server"
|
||||
export OP_CONNECT_TOKEN="your-connect-token"
|
||||
|
||||
# Then op commands use Connect instead of 1Password.com
|
||||
op item get "Item Title"
|
||||
```
|
||||
|
||||
## Output Formats
|
||||
|
||||
Valid values: `json` or `human-readable` (default).
|
||||
|
||||
```bash
|
||||
op item list --format=json # Machine-readable JSON
|
||||
op item get "Item" --format=json # Full item JSON
|
||||
op item list # Human-readable (default)
|
||||
op vault list --format=json # Vaults as JSON
|
||||
```
|
||||
|
||||
## Useful Patterns
|
||||
|
||||
```bash
|
||||
# Find item by field value (search)
|
||||
op item list --format=json | \
|
||||
python3 -c "import sys,json; [print(i['title']) for i in json.load(sys.stdin)]"
|
||||
|
||||
# Export all items in a vault to JSON (backup)
|
||||
op item list --vault Dev --format=json | \
|
||||
python3 -c "import sys,json; ids=[i['id'] for i in json.load(sys.stdin)]"
|
||||
# (then loop to get each)
|
||||
|
||||
# Check if a specific item exists
|
||||
op item get "My Item" &>/dev/null && echo "exists" || echo "not found"
|
||||
|
||||
# Get item ID (for scripting)
|
||||
op item get "My Item" --format=json | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])"
|
||||
```
|
||||
120
.claude/skills/1password/references/secret_references.md
Normal file
120
.claude/skills/1password/references/secret_references.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# 1Password Secret References
|
||||
|
||||
Secret references are the safest way to use secrets — they point to 1Password without exposing actual values in code or config files.
|
||||
|
||||
## Syntax
|
||||
|
||||
```
|
||||
op://vault/item/field
|
||||
op://vault/item/section/field
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
```bash
|
||||
op://Dev/Anthropic/api_key
|
||||
op://Personal/AWS/access_key_id
|
||||
op://Dev/Supabase/section/service_key
|
||||
```
|
||||
|
||||
## Reading a Secret Reference
|
||||
|
||||
```bash
|
||||
# Single secret
|
||||
op read "op://Dev/Anthropic/api_key"
|
||||
|
||||
# Into a variable
|
||||
export ANTHROPIC_API_KEY=$(op read "op://Dev/Anthropic/api_key")
|
||||
|
||||
# Multiple secrets via op run
|
||||
op run --env-file=.env.tpl -- your-command
|
||||
```
|
||||
|
||||
## .env Template Files
|
||||
|
||||
Store references in a `.env.tpl` file (safe to commit to **private** repos):
|
||||
|
||||
> **Privacy note:** `.env.tpl` contains your vault names, item names, and field names —
|
||||
> e.g. `op://Dev/Anthropic/api_key`. This reveals the structure of your 1Password vault
|
||||
> to anyone who can read the file. For **private repos**, this is fine. For **public repos**,
|
||||
> consider whether your vault/item naming reveals anything sensitive (client names, internal
|
||||
> service names, etc.). Real secret values are never exposed — only the structure.
|
||||
|
||||
```bash
|
||||
# .env.tpl — commit this
|
||||
ANTHROPIC_API_KEY=op://Dev/Anthropic/api_key
|
||||
N8N_API_KEY=op://Dev/n8n/api_key
|
||||
SUPABASE_SERVICE_KEY=op://Dev/Supabase/service_key
|
||||
NOTION_TOKEN=op://Dev/Notion/api_token
|
||||
```
|
||||
|
||||
Then inject at runtime:
|
||||
```bash
|
||||
# ✅ RECOMMENDED — run your command with secrets injected into subprocess only
|
||||
op run --env-file=.env.tpl -- npm start
|
||||
op run --env-file=.env.tpl -- node server.js
|
||||
op run --env-file=.env.tpl -- docker compose up
|
||||
|
||||
# ✅ OK — read a single secret into a variable for immediate use
|
||||
export ANTHROPIC_API_KEY=$(op read "op://Dev/Anthropic/api_key")
|
||||
|
||||
# ⚠️ AVOID — sourcing op run output exposes secrets in current shell
|
||||
# and is unsafe if any secret value contains shell metacharacters like $(...):
|
||||
# source <(op run --env-file=.env.tpl -- env) ← DON'T DO THIS
|
||||
|
||||
# ⚠️ AVOID — writing resolved secrets to disk (don't commit .env)
|
||||
# op run --env-file=.env.tpl -- env > .env ← only if truly necessary
|
||||
```
|
||||
|
||||
## In Config Files
|
||||
|
||||
Claude Desktop (`claude_desktop_config.json`):
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-server": {
|
||||
"command": "op",
|
||||
"args": ["run", "--", "node", "server.js"],
|
||||
"env": {
|
||||
"API_KEY": "op://Dev/MyServer/api_key"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Docker Compose:
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
image: myapp
|
||||
environment:
|
||||
- DATABASE_URL=op://Dev/Postgres/connection_string
|
||||
```
|
||||
Run with: `op run -- docker compose up`
|
||||
|
||||
n8n (environment injection):
|
||||
```bash
|
||||
# In your n8n startup script
|
||||
op run --env-file=n8n.env.tpl -- docker compose up n8n
|
||||
```
|
||||
|
||||
## Finding Field Names
|
||||
|
||||
```bash
|
||||
# List all fields in an item
|
||||
op item get "Item Name" --format=json | \
|
||||
python3 -c "import sys,json; [print(f['label']) for f in json.load(sys.stdin)['fields'] if f.get('value')]"
|
||||
|
||||
# Or view interactively
|
||||
op item get "Item Name"
|
||||
```
|
||||
|
||||
## Common Field Names by Category
|
||||
|
||||
| Category | Common Fields |
|
||||
|----------|---------------|
|
||||
| API_CREDENTIAL | `api_key`, `credential`, `token` |
|
||||
| LOGIN | `username`, `password` |
|
||||
| DATABASE | `connection_string`, `host`, `port`, `username`, `password` |
|
||||
| SECURE_NOTE | `notesPlain` |
|
||||
| SERVER | `hostname`, `port`, `username`, `password` |
|
||||
75
.claude/skills/1password/scripts/check_setup.sh
Executable file
75
.claude/skills/1password/scripts/check_setup.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
# check_setup.sh — Verify 1Password CLI is installed and authenticated
|
||||
# Usage: bash check_setup.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
check() {
|
||||
local label="$1"
|
||||
local cmd="$2"
|
||||
if eval "$cmd" &>/dev/null; then
|
||||
echo " ✅ $label"
|
||||
((PASS++)) || true
|
||||
else
|
||||
echo " ❌ $label"
|
||||
((FAIL++)) || true
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== 1Password CLI Setup Check ==="
|
||||
echo ""
|
||||
|
||||
# 1. CLI installed
|
||||
check "op CLI installed" "command -v op"
|
||||
|
||||
# 2. Version
|
||||
if command -v op &>/dev/null; then
|
||||
echo " ℹ️ Version: $(op --version)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- Authentication ---"
|
||||
|
||||
# 3. Signed in
|
||||
check "Signed in to 1Password" "op account list 2>/dev/null | grep -q '.'"
|
||||
|
||||
# 4. Can list vaults
|
||||
check "Can list vaults" "op vault list &>/dev/null"
|
||||
|
||||
# Show accounts if authenticated
|
||||
if op account list &>/dev/null 2>&1; then
|
||||
echo ""
|
||||
echo " Accounts:"
|
||||
op account list 2>/dev/null | tail -n +2 | while read -r line; do
|
||||
echo " • $line"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo " Vaults:"
|
||||
op vault list --format=json 2>/dev/null | \
|
||||
python3 -c "import sys,json; [print(f' • {v[\"name\"]} ({v[\"id\"]})') for v in json.load(sys.stdin)]" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- Environment ---"
|
||||
|
||||
# 5. OP_SERVICE_ACCOUNT_TOKEN (CI/CD pattern)
|
||||
if [[ -n "${OP_SERVICE_ACCOUNT_TOKEN:-}" ]]; then
|
||||
echo " ✅ OP_SERVICE_ACCOUNT_TOKEN is set (service account mode)"
|
||||
else
|
||||
echo " ℹ️ OP_SERVICE_ACCOUNT_TOKEN not set (interactive/desktop app mode)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "==================================="
|
||||
if [[ $FAIL -eq 0 ]]; then
|
||||
echo "✅ All checks passed. 1Password CLI is ready."
|
||||
else
|
||||
echo "⚠️ $FAIL check(s) failed. See above."
|
||||
echo ""
|
||||
echo "Install: https://developer.1password.com/docs/cli/get-started/"
|
||||
echo "Sign in: op signin"
|
||||
fi
|
||||
142
.claude/skills/1password/scripts/env_from_op.sh
Executable file
142
.claude/skills/1password/scripts/env_from_op.sh
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env bash
|
||||
# env_from_op.sh — Generate a .env file from 1Password items
|
||||
#
|
||||
# Usage:
|
||||
# bash env_from_op.sh # Interactive: prompts for vault + items
|
||||
# bash env_from_op.sh --vault Dev # Use specific vault
|
||||
# bash env_from_op.sh --item "My Project" # Export all fields from one item
|
||||
# bash env_from_op.sh --output .env # Write to file (default: .env)
|
||||
# bash env_from_op.sh --dry-run # Print without writing
|
||||
#
|
||||
# Output format:
|
||||
# FIELD_NAME=op://Vault/Item/field # Secret references (safest)
|
||||
# FIELD_NAME=actual_value # Resolved values (with --resolve)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VAULT=""
|
||||
ITEM=""
|
||||
OUTPUT=".env"
|
||||
DRY_RUN=false
|
||||
RESOLVE=false
|
||||
|
||||
# Parse args
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--vault) VAULT="$2"; shift 2 ;;
|
||||
--item) ITEM="$2"; shift 2 ;;
|
||||
--output) OUTPUT="$2"; shift 2 ;;
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
--resolve) RESOLVE=true; shift ;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check op is available
|
||||
if ! command -v op &>/dev/null; then
|
||||
echo "❌ 1Password CLI (op) not found. Install: https://developer.1password.com/docs/cli/get-started/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If no item specified, list items and prompt
|
||||
if [[ -z "$ITEM" ]]; then
|
||||
echo "Available items in vault '${VAULT:-all vaults}':"
|
||||
if [[ -n "$VAULT" ]]; then
|
||||
op item list --vault "$VAULT" --format=json | \
|
||||
python3 -c "import sys,json; [print(f' {i[\"title\"]}') for i in json.load(sys.stdin)]"
|
||||
else
|
||||
op item list --format=json | \
|
||||
python3 -c "import sys,json; [print(f' [{i[\"vault\"][\"name\"]}] {i[\"title\"]}') for i in json.load(sys.stdin)]"
|
||||
fi
|
||||
echo ""
|
||||
read -rp "Enter item title: " ITEM
|
||||
fi
|
||||
|
||||
echo "Fetching '${ITEM}' from 1Password..."
|
||||
|
||||
# Get item as JSON
|
||||
if [[ -n "$VAULT" ]]; then
|
||||
ITEM_JSON=$(op item get "$ITEM" --vault "$VAULT" --format=json)
|
||||
else
|
||||
ITEM_JSON=$(op item get "$ITEM" --format=json)
|
||||
fi
|
||||
|
||||
VAULT_NAME=$(echo "$ITEM_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['vault']['name'])")
|
||||
ITEM_TITLE=$(echo "$ITEM_JSON" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['title'])")
|
||||
|
||||
# Build .env content
|
||||
ENV_CONTENT=$(echo "$ITEM_JSON" | python3 - <<'PYEOF'
|
||||
import sys, json, re
|
||||
|
||||
data = json.load(sys.stdin)
|
||||
vault = data['vault']['name']
|
||||
title = data['title']
|
||||
lines = []
|
||||
|
||||
SKIP_LABELS = {'username', 'password', 'notesPlain', 'notes'}
|
||||
SKIP_TYPES = {'CONCEALED'} if False else set() # resolved mode: don't skip
|
||||
|
||||
for field in data.get('fields', []):
|
||||
label = field.get('label', '')
|
||||
value = field.get('value', '')
|
||||
field_id = field.get('id', '')
|
||||
ftype = field.get('type', '')
|
||||
|
||||
# Skip empty, metadata, or UI-only fields
|
||||
if not value or not label:
|
||||
continue
|
||||
if label.lower() in {'username', 'notesplain', 'notes', 'password'} and ftype not in {'CONCEALED', 'URL'}:
|
||||
continue
|
||||
|
||||
# Convert label to ENV_VAR format
|
||||
env_key = re.sub(r'[^A-Z0-9_]', '_', label.upper().replace(' ', '_').replace('-', '_'))
|
||||
env_key = re.sub(r'_+', '_', env_key).strip('_')
|
||||
|
||||
# Use secret reference (safer than raw value)
|
||||
ref = f"op://{vault}/{title}/{label}"
|
||||
lines.append(f"{env_key}={ref}")
|
||||
|
||||
print('\n'.join(lines))
|
||||
PYEOF
|
||||
)
|
||||
|
||||
# Handle resolve flag — replace refs with real values
|
||||
if $RESOLVE; then
|
||||
echo "⚠️ Writing resolved values (actual secrets). Handle carefully."
|
||||
FINAL_CONTENT=""
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^([A-Z_]+)=(op://.+)$ ]]; then
|
||||
key="${BASH_REMATCH[1]}"
|
||||
ref="${BASH_REMATCH[2]}"
|
||||
value=$(op read "$ref" 2>/dev/null || echo "ERROR_READING")
|
||||
FINAL_CONTENT+="${key}=${value}"$'\n'
|
||||
else
|
||||
FINAL_CONTENT+="$line"$'\n'
|
||||
fi
|
||||
done <<< "$ENV_CONTENT"
|
||||
ENV_CONTENT="$FINAL_CONTENT"
|
||||
fi
|
||||
|
||||
# Header
|
||||
HEADER="# Generated from 1Password: ${VAULT_NAME}/${ITEM_TITLE}
|
||||
# Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
# Load with: op run --env-file=.env -- <command>
|
||||
# or: eval \$(op run --env-file=.env -- env | grep KEY)
|
||||
|
||||
"
|
||||
|
||||
FULL_CONTENT="${HEADER}${ENV_CONTENT}"
|
||||
|
||||
if $DRY_RUN; then
|
||||
echo ""
|
||||
echo "--- .env preview ---"
|
||||
echo "$FULL_CONTENT"
|
||||
echo "--- end ---"
|
||||
else
|
||||
echo "$FULL_CONTENT" > "$OUTPUT"
|
||||
echo "✅ Written to $OUTPUT (${#ENV_CONTENT} chars, $(echo "$ENV_CONTENT" | grep -c '=' || true) vars)"
|
||||
echo ""
|
||||
echo "To use:"
|
||||
echo " op run --env-file=$OUTPUT -- your-command"
|
||||
echo " source <(op run --env-file=$OUTPUT -- env)"
|
||||
fi
|
||||
52
.claude/skills/1password/scripts/launch-in-terminal.sh
Executable file
52
.claude/skills/1password/scripts/launch-in-terminal.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# launch-in-terminal.sh — Open a script in a NEW Terminal.app window
|
||||
#
|
||||
# This is how the 1Password skill keeps secrets OUT of Claude Code.
|
||||
# Claude generates the script, then calls this launcher.
|
||||
# The script runs in Terminal.app — Claude never sees what you type.
|
||||
#
|
||||
# Usage:
|
||||
# bash launch-in-terminal.sh /path/to/script.sh
|
||||
# bash launch-in-terminal.sh /path/to/script.sh "window title"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_PATH="${1:-}"
|
||||
TITLE="${2:-1Password Setup}"
|
||||
|
||||
if [[ -z "$SCRIPT_PATH" ]]; then
|
||||
echo "Usage: bash launch-in-terminal.sh /path/to/script.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$SCRIPT_PATH" ]]; then
|
||||
echo "❌ Script not found: $SCRIPT_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x "$SCRIPT_PATH"
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " Opening Terminal.app to collect secrets"
|
||||
echo " Script: $SCRIPT_PATH"
|
||||
echo ""
|
||||
echo " ⚠️ Type your secrets in the Terminal"
|
||||
echo " window that is about to open."
|
||||
echo " Claude Code cannot see that window."
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
osascript <<APPLESCRIPT
|
||||
tell application "Terminal"
|
||||
activate
|
||||
set newTab to do script "echo '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'; echo ' ${TITLE}'; echo ' Type secrets here — Claude Code cannot see this window'; echo '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'; echo ''; bash ${SCRIPT_PATH}"
|
||||
end tell
|
||||
APPLESCRIPT
|
||||
|
||||
echo "✅ Terminal.app opened. Complete the prompts there, then return here."
|
||||
echo " (This window will wait for you to press Enter when done)"
|
||||
echo ""
|
||||
read -rp "Press Enter once you've finished in Terminal.app... "
|
||||
echo ""
|
||||
echo "Continuing..."
|
||||
124
.claude/skills/1password/scripts/store-mcp-credentials.sh
Executable file
124
.claude/skills/1password/scripts/store-mcp-credentials.sh
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env bash
|
||||
# store-mcp-credentials.sh — Store MCP server credentials in 1Password
|
||||
#
|
||||
# ⚠️ RUN THIS IN TERMINAL.APP — NOT IN CLAUDE CODE
|
||||
# Claude Code can see everything typed in its terminal.
|
||||
# Open Terminal.app separately, then run this script.
|
||||
#
|
||||
# Usage (Claude will generate a pre-filled version for you):
|
||||
# bash store-mcp-credentials.sh \
|
||||
# --vault Dev \
|
||||
# --item "My MCP Server" \
|
||||
# --set "url=https://api.example.com" \
|
||||
# --set "log_level=error" \
|
||||
# --secret "api_key" \
|
||||
# --secret "webhook_secret"
|
||||
#
|
||||
# Options:
|
||||
# --vault 1Password vault name (default: Dev)
|
||||
# --item Item title in 1Password
|
||||
# --set Non-secret field: key=value (pre-filled, visible)
|
||||
# --secret Secret field: prompted with hidden input
|
||||
# --update Update existing item instead of creating new
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VAULT="Dev"
|
||||
ITEM=""
|
||||
UPDATE=false
|
||||
declare -a SET_FIELDS=()
|
||||
declare -a SECRET_FIELDS=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--vault) VAULT="$2"; shift 2 ;;
|
||||
--item) ITEM="$2"; shift 2 ;;
|
||||
--set) SET_FIELDS+=("$2"); shift 2 ;;
|
||||
--secret) SECRET_FIELDS+=("$2"); shift 2 ;;
|
||||
--update) UPDATE=true; shift ;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$ITEM" ]]; then
|
||||
read -rp "Item title in 1Password: " ITEM
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " Storing: $ITEM"
|
||||
echo " Vault: $VAULT"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo ""
|
||||
|
||||
# Show pre-filled fields
|
||||
if [[ ${#SET_FIELDS[@]} -gt 0 ]]; then
|
||||
echo "Pre-filled fields:"
|
||||
for field in "${SET_FIELDS[@]}"; do
|
||||
key="${field%%=*}"
|
||||
val="${field#*=}"
|
||||
echo " $key = $val"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Prompt for secret fields
|
||||
declare -a SECRET_VALUES=()
|
||||
if [[ ${#SECRET_FIELDS[@]} -gt 0 ]]; then
|
||||
echo "Enter secret values (input is hidden):"
|
||||
for field in "${SECRET_FIELDS[@]}"; do
|
||||
read -rsp " $field: " secret_val
|
||||
echo ""
|
||||
SECRET_VALUES+=("${field}[password]=${secret_val}")
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Build op field args for non-secret fields
|
||||
declare -a OP_FIELDS=()
|
||||
for field in "${SET_FIELDS[@]}"; do
|
||||
key="${field%%=*}"
|
||||
val="${field#*=}"
|
||||
OP_FIELDS+=("${key}[text]=${val}")
|
||||
done
|
||||
|
||||
# Combine all fields
|
||||
ALL_FIELDS=("${OP_FIELDS[@]+"${OP_FIELDS[@]}"}" "${SECRET_VALUES[@]+"${SECRET_VALUES[@]}"}")
|
||||
|
||||
echo "Saving to 1Password..."
|
||||
|
||||
if $UPDATE; then
|
||||
op item edit "$ITEM" --vault "$VAULT" "${ALL_FIELDS[@]}"
|
||||
echo ""
|
||||
echo "✅ Updated '$ITEM' in vault '$VAULT'"
|
||||
else
|
||||
# Try create, fall back to update if already exists
|
||||
if op item get "$ITEM" --vault "$VAULT" &>/dev/null 2>&1; then
|
||||
echo " Item already exists — updating instead..."
|
||||
op item edit "$ITEM" --vault "$VAULT" "${ALL_FIELDS[@]}"
|
||||
echo ""
|
||||
echo "✅ Updated '$ITEM' in vault '$VAULT'"
|
||||
else
|
||||
op item create \
|
||||
--category API_CREDENTIAL \
|
||||
--title "$ITEM" \
|
||||
--vault "$VAULT" \
|
||||
"${ALL_FIELDS[@]}"
|
||||
echo ""
|
||||
echo "✅ Created '$ITEM' in vault '$VAULT'"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Secret references for your config:"
|
||||
for field in "${SET_FIELDS[@]}"; do
|
||||
key="${field%%=*}"
|
||||
echo " op://${VAULT}/${ITEM}/${key}"
|
||||
done
|
||||
for field in "${SECRET_FIELDS[@]}"; do
|
||||
echo " op://${VAULT}/${ITEM}/${field}"
|
||||
done
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo " Done. You can close this terminal."
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
91
.claude/skills/1password/scripts/store_secret.sh
Executable file
91
.claude/skills/1password/scripts/store_secret.sh
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bash
|
||||
# store_secret.sh — Store or update a secret in 1Password
|
||||
#
|
||||
# Usage:
|
||||
# bash store_secret.sh --title "My API Key" --field "api_key" --value "sk-..."
|
||||
# bash store_secret.sh --title "Project Creds" --vault Dev --category API_CREDENTIAL
|
||||
# bash store_secret.sh --update --title "Existing Item" --field "api_key" --value "new-value"
|
||||
# bash store_secret.sh --from-env MY_VAR # Store from environment variable
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TITLE=""
|
||||
FIELD="credential"
|
||||
VALUE=""
|
||||
VAULT=""
|
||||
CATEGORY="API_CREDENTIAL"
|
||||
UPDATE=false
|
||||
FROM_ENV=""
|
||||
GENERATE=false
|
||||
GENERATE_LENGTH=32
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--title) TITLE="$2"; shift 2 ;;
|
||||
--field) FIELD="$2"; shift 2 ;;
|
||||
--value) VALUE="$2"; shift 2 ;;
|
||||
--vault) VAULT="$2"; shift 2 ;;
|
||||
--category) CATEGORY="$2"; shift 2 ;;
|
||||
--update) UPDATE=true; shift ;;
|
||||
--from-env) FROM_ENV="$2"; shift 2 ;;
|
||||
--generate) GENERATE=true; shift ;;
|
||||
--length) GENERATE_LENGTH="$2"; shift 2 ;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate
|
||||
if [[ -z "$TITLE" ]]; then
|
||||
read -rp "Item title: " TITLE
|
||||
fi
|
||||
|
||||
# Get value from env var if requested
|
||||
if [[ -n "$FROM_ENV" ]]; then
|
||||
VALUE="${!FROM_ENV:-}"
|
||||
if [[ -z "$VALUE" ]]; then
|
||||
echo "❌ Environment variable $FROM_ENV is not set or empty"
|
||||
exit 1
|
||||
fi
|
||||
FIELD="${FROM_ENV}"
|
||||
echo "Using value from \$$FROM_ENV"
|
||||
fi
|
||||
|
||||
# Generate a secure credential if requested
|
||||
if $GENERATE; then
|
||||
VALUE=$(openssl rand -base64 "$GENERATE_LENGTH" | tr -d '=+/' | head -c "$GENERATE_LENGTH")
|
||||
echo "🔐 Generated secure credential ($GENERATE_LENGTH chars)"
|
||||
fi
|
||||
|
||||
# Prompt for value if still empty
|
||||
if [[ -z "$VALUE" ]]; then
|
||||
read -rsp "Value (hidden): " VALUE
|
||||
echo ""
|
||||
fi
|
||||
|
||||
VAULT_FLAG=""
|
||||
[[ -n "$VAULT" ]] && VAULT_FLAG="--vault $VAULT"
|
||||
|
||||
if $UPDATE; then
|
||||
echo "Updating '${FIELD}' in '${TITLE}'..."
|
||||
op item edit "$TITLE" $VAULT_FLAG "${FIELD}[password]=${VALUE}"
|
||||
echo "✅ Updated '${FIELD}' in '${TITLE}'"
|
||||
else
|
||||
echo "Creating '${TITLE}' in 1Password..."
|
||||
RESULT=$(op item create \
|
||||
--category "$CATEGORY" \
|
||||
--title "$TITLE" \
|
||||
$VAULT_FLAG \
|
||||
"${FIELD}[password]=${VALUE}" \
|
||||
--format=json)
|
||||
|
||||
ITEM_ID=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
||||
VAULT_NAME=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin)['vault']['name'])")
|
||||
|
||||
echo "✅ Created '${TITLE}' (ID: ${ITEM_ID})"
|
||||
echo ""
|
||||
echo "Secret reference:"
|
||||
echo " op://${VAULT_NAME}/${TITLE}/${FIELD}"
|
||||
echo ""
|
||||
echo "Read it back:"
|
||||
echo " op read \"op://${VAULT_NAME}/${TITLE}/${FIELD}\""
|
||||
fi
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -63,3 +63,7 @@ api/.env
|
||||
.mcp.json
|
||||
Pictures/
|
||||
.grepai/
|
||||
# Radio processor
|
||||
projects/radio-show/audio-processor/test-data/*.mp3
|
||||
projects/radio-show/audio-processor/*.egg-info/
|
||||
|
||||
|
||||
@@ -37,16 +37,16 @@ Windows> choco install git python nodejs
|
||||
```bash
|
||||
# Windows
|
||||
Windows> cd D:\
|
||||
Windows> git clone ssh://azcomputerguru@172.16.3.20:2222/azcomputerguru/claudetools.git ClaudeTools
|
||||
Windows> git clone https://git.azcomputerguru.com/azcomputerguru/claudetools.git ClaudeTools
|
||||
Windows> cd ClaudeTools
|
||||
|
||||
# Mac
|
||||
Mac> cd ~/Projects # or wherever you want it
|
||||
Mac> git clone ssh://azcomputerguru@172.16.3.20:2222/azcomputerguru/claudetools.git ClaudeTools
|
||||
Mac> git clone https://git.azcomputerguru.com/azcomputerguru/claudetools.git ClaudeTools
|
||||
Mac> cd ClaudeTools
|
||||
```
|
||||
|
||||
**Note:** You'll need SSH access to the Gitea server (172.16.3.20:2222)
|
||||
**Note:** Uses HTTPS to Gitea at git.azcomputerguru.com
|
||||
|
||||
**For This Guide:**
|
||||
- Windows path: `D:\ClaudeTools`
|
||||
|
||||
68
STAGE-IMPORT-INSTRUCTIONS.md
Normal file
68
STAGE-IMPORT-INSTRUCTIONS.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Stage TXT Import Task
|
||||
# Date: 2026-03-28
|
||||
# Context: CTONWTXT.BAT now uploads C:\STAGE\*.TXT from DOS machines to T:\STAGE\%MACHINE%\
|
||||
|
||||
## What happened
|
||||
|
||||
1. CTONWTXT.BAT was never being called -- fixed, now called from CTONW.BAT on every boot
|
||||
2. Destination changed from broken X: (Novell serve.sys check) to T:\STAGE\%MACHINE%\
|
||||
3. DOS 6.22 can't MD on existing dirs without error, so dirs are pre-created on NAS
|
||||
4. All TS-* machine folders pre-created under /data/test/STAGE/ on D2TESTNAS
|
||||
|
||||
## What needs to run
|
||||
|
||||
Save the script below as C:\Shares\testdatadb\import-all-stage.js and run it:
|
||||
|
||||
cd C:\Shares\testdatadb
|
||||
node import-all-stage.js
|
||||
|
||||
## What it does
|
||||
|
||||
- Scans \\D2TESTNAS\test\STAGE\TS-*\*.TXT (~8,100 files across 10 machines)
|
||||
- Parses each TXT datasheet (Date, Model, SN)
|
||||
- Decodes hex-prefix serial numbers for 8.3 filename encoding:
|
||||
- Letter prefix = hex digit: A=10, B=11, C=12, ..., H=17, etc.
|
||||
- Example: H8236-12.TXT has SN: 178236-12 inside the file
|
||||
- Example: A819-1.TXT has SN: A819-1 inside -> decoded to 10819-1
|
||||
- The SN line inside H-prefix files already has the full numeric serial
|
||||
- The SN line inside A-prefix files still has the encoded serial
|
||||
- Cross-references against testdata.db by (serial_number, model_number)
|
||||
- Inserts MISSING records as log_type='SHT' with test_station from folder name
|
||||
- Copies ALL files to X:\For_Web\{decoded_serial}.TXT (the web share)
|
||||
|
||||
## Machines with data
|
||||
|
||||
TS-4L: 3,082 files (largest)
|
||||
TS-4R: 2,741 files
|
||||
TS-1R: 509 files
|
||||
TS-8R: 478 files
|
||||
TS-3R: 435 files
|
||||
TS-11R: 325 files
|
||||
TS-8L: 285 files
|
||||
TS-11L: 248 files
|
||||
TS-27: 10 files (already imported this session)
|
||||
TS-1L: 1 file
|
||||
|
||||
## Serial number encoding (8.3 filename scheme)
|
||||
|
||||
The QuickBASIC ATE software encodes long serial numbers to fit DOS 8.3 filenames.
|
||||
The first two digits get replaced with a hex letter if the serial is too long:
|
||||
|
||||
178236-12 -> H8236-12.TXT (17 -> H, which is char code 72, 72-55=17)
|
||||
10819-1 -> A819-1.TXT (10 -> A, which is char code 65, 65-55=10)
|
||||
|
||||
Decode: letter.charCodeAt(0) - 55 = numeric prefix
|
||||
Only applies if filename starts with [A-Z] followed by digits.
|
||||
|
||||
## TS-27 already done
|
||||
|
||||
10 files from TS-27 were already imported earlier this session into the DB as SHT records.
|
||||
The import script uses INSERT OR REPLACE so re-running is safe.
|
||||
|
||||
## Previous CTONWTXT.BAT issues (resolved)
|
||||
|
||||
- v1.0: Never called, checked for Novell serve.sys, used X: drive parameter
|
||||
- v2.0: Called from CTONW, but used mixed-case "Stage" path -> failed on DOS
|
||||
- v2.1: All uppercase STAGE, but had MD commands that fail on existing dirs
|
||||
- v2.2: Same issue
|
||||
- v2.3: Removed MD entirely, dirs pre-created on NAS. CURRENT VERSION.
|
||||
BIN
Test Datasheets/DF-Test-Detail.PDF
Normal file
BIN
Test Datasheets/DF-Test-Detail.PDF
Normal file
Binary file not shown.
80
Test Datasheets/DFWDS/DFWDS_NAMES.txt
Normal file
80
Test Datasheets/DFWDS/DFWDS_NAMES.txt
Normal file
@@ -0,0 +1,80 @@
|
||||
DATASHEET FOLDER NAME,X:\Test_Datasheets
|
||||
INVALID FILE MOVE FOLDER,X:\Bad_Datasheets
|
||||
LOG FILE NAME,DFWDS
|
||||
LOG FILE FOLDER,X:\Datasheets_Log
|
||||
WEB FOLDER,X:\For_Web
|
||||
OPERATION,WEBMOVE
|
||||
|
||||
Last updated: 2015-06-08
|
||||
|
||||
The first six lines of this file are folder and file names required by
|
||||
the Dataforth Website Datasheet program (DFWDS.exe). Each line consists
|
||||
of the parameter name (in all CAPS), followed by a comma, followed by
|
||||
the file or folder name (not in quotes) or operation. A space is
|
||||
allowed after the comma separator.
|
||||
|
||||
The six lines parameter lines must contain only the allowed parameters
|
||||
and data, in this specified format, for the program to operate properly.
|
||||
Any lines below these six lines are not read by the program, and can
|
||||
consist of comments or instructions (such as these).
|
||||
|
||||
The location and name of this file (usually C:\DFWDS\DFWDS_NAMES.TXT) is
|
||||
hardcoded in the program.
|
||||
|
||||
Descriptions of the six required lines (along with the required parameter
|
||||
names) are shown below:
|
||||
|
||||
First line:
|
||||
-----------
|
||||
DATASHEET FOLDER NAME: This is the location of the folder containing the
|
||||
datasheet files that will eventually be copied to the Dataforth website.
|
||||
|
||||
Second line:
|
||||
------------
|
||||
INVALID FILE MOVE FOLDER: This is the location of the folder to which
|
||||
invalid files in the datasheet folder will be moved.
|
||||
|
||||
Third line:
|
||||
-----------
|
||||
LOG FILE NAME: This is the name of the file that logs the operation of the
|
||||
Dataforth Website Datasheet program (DFWDS.exe), including invalid file
|
||||
moves and datasheet file renaming. NOTE: This is the file name (only),
|
||||
and does NOT include the ".log" extension.
|
||||
|
||||
Fourth line:
|
||||
------------
|
||||
LOG FILE FOLDER: This is the location of the folder containing the log
|
||||
file for the DFWDS.exe program.
|
||||
|
||||
Fifth line:
|
||||
WEB FOLDER: This is the location of the folder to which the valid
|
||||
datasheet files (including renamed files) are moved if the "OPERATION"
|
||||
parameter (see below) is "WEBMOVE".
|
||||
|
||||
Sixth line:
|
||||
-----------
|
||||
OPERATION: This parameter controls the operation of the program, and
|
||||
can only be one of the values described below:
|
||||
-------------------------------------
|
||||
COUNT causes the program to only count the invalid files
|
||||
and files that should be renamed.
|
||||
|
||||
LISTALL causes the program to list all of the files found in the
|
||||
datasheet folder.
|
||||
|
||||
LISTBAD causes the program to list all of the invalid ("bad") files
|
||||
found in the datasheet folder.
|
||||
|
||||
LISTRENAME causes the program to list all of the datasheet files in
|
||||
the datasheet folder that have DOS-encoded names that need to be
|
||||
renamed to match the module serial number contained in the file.
|
||||
|
||||
INPLACE renames the appropriate files in their current directory
|
||||
(specified by the "DATASHEET FOLDER NAME" parameter - see above), but
|
||||
moves the invalid files to the directory specified by the
|
||||
"INVALID FILE MOVE FOLDER" parameter (see above).
|
||||
|
||||
WEBMOVE moves the invalid files to the "INVALID FILE MOVE FOLDER"
|
||||
directory, but also moves the valid datasheet files (including those
|
||||
that have been renamed) to the folder specified by the "WEB FOLDER"
|
||||
parameter (see above).
|
||||
1388
Test Datasheets/QB-Source/DB8BMAIN.BAS
Normal file
1388
Test Datasheets/QB-Source/DB8BMAIN.BAS
Normal file
File diff suppressed because it is too large
Load Diff
2380
Test Datasheets/QB-Source/KDSCOUT1.BAS
Normal file
2380
Test Datasheets/QB-Source/KDSCOUT1.BAS
Normal file
File diff suppressed because it is too large
Load Diff
3168
Test Datasheets/QB-Source/NLIBATED-DSCA.BAS
Normal file
3168
Test Datasheets/QB-Source/NLIBATED-DSCA.BAS
Normal file
File diff suppressed because it is too large
Load Diff
3222
Test Datasheets/QB-Source/NLIBATED-DSCT.BAS
Normal file
3222
Test Datasheets/QB-Source/NLIBATED-DSCT.BAS
Normal file
File diff suppressed because it is too large
Load Diff
3223
Test Datasheets/QB-Source/NLIBATED.BAS
Normal file
3223
Test Datasheets/QB-Source/NLIBATED.BAS
Normal file
File diff suppressed because it is too large
Load Diff
3506
Test Datasheets/QB-Source/TEST5B1E.BAS
Normal file
3506
Test Datasheets/QB-Source/TEST5B1E.BAS
Normal file
File diff suppressed because it is too large
Load Diff
3367
Test Datasheets/QB-Source/TEST5B2E.BAS
Normal file
3367
Test Datasheets/QB-Source/TEST5B2E.BAS
Normal file
File diff suppressed because it is too large
Load Diff
1731
Test Datasheets/QB-Source/TEST7B1C.BAS
Normal file
1731
Test Datasheets/QB-Source/TEST7B1C.BAS
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Test Datasheets/QB-Source/TESTPW17.BAS
Normal file
BIN
Test Datasheets/QB-Source/TESTPW17.BAS
Normal file
Binary file not shown.
3473
Test Datasheets/QB-Source/TST5SCT1.BAS
Normal file
3473
Test Datasheets/QB-Source/TST5SCT1.BAS
Normal file
File diff suppressed because it is too large
Load Diff
2052
Test Datasheets/QB-Source/TST5SCT2.BAS
Normal file
2052
Test Datasheets/QB-Source/TST5SCT2.BAS
Normal file
File diff suppressed because it is too large
Load Diff
194
Test Datasheets/README.md
Normal file
194
Test Datasheets/README.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# Claude Instance Context: Test Datasheets Investigation (AD1)
|
||||
|
||||
**Purpose:** You are a Claude Code instance running on AD1 (192.168.0.27) at Dataforth's facility. Your job is to investigate the TestDataSheetUploader tool and the test datasheet workflow -- where files come from, where they go, and how this integrates with the DOS test machines.
|
||||
|
||||
**This is a temporary investigation instance.** Once findings are documented and synced to Gitea, this instance will be removed.
|
||||
|
||||
---
|
||||
|
||||
## Your Mission
|
||||
|
||||
1. **Find where test datasheets are generated** -- which machine(s), which software, what path
|
||||
2. **Find where they end up** -- the server-side path is `C:\inetpub\wwwroot\dataforth.com\WebShare\ProcessCheckOutTestFolder\` on whatever runs www.dataforth.com
|
||||
3. **Determine if this uploader is still in active use** or if the workflow changed
|
||||
4. **Document the full datasheet pipeline** -- from DOS test machine output through to the website
|
||||
5. **Sync your findings back to Gitea** so the coordinator instance can see them
|
||||
|
||||
---
|
||||
|
||||
## Gitea Sync (How to Push Findings)
|
||||
|
||||
The ClaudeTools repo is hosted on Gitea. Clone and push your findings here:
|
||||
|
||||
```bash
|
||||
# Clone the repo
|
||||
git clone https://mike%40azcomputerguru.com:Gptf%2A77ttb123%21%40%23-git@git.azcomputerguru.com/azcomputerguru/claudetools.git
|
||||
cd claudetools
|
||||
|
||||
# Your working area
|
||||
# clients/dataforth/dos-test-machines/Test Datasheets/
|
||||
|
||||
# Commit and push findings
|
||||
git add -A
|
||||
git commit -m "AD1 investigation: test datasheet pipeline findings"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
**Gitea Credentials (plaintext, temporary use only):**
|
||||
- URL: https://git.azcomputerguru.com
|
||||
- User: mike@azcomputerguru.com
|
||||
- Password: Gptf*77ttb123!@#-git
|
||||
|
||||
---
|
||||
|
||||
## Network Context (Dataforth Engineering Network)
|
||||
|
||||
| Device | IP | Role | Credentials |
|
||||
|--------|-----|------|-------------|
|
||||
| AD1 (you are here) | 192.168.0.27 | Primary Domain Controller | INTRANET\sysadmin / Paper123!@# |
|
||||
| AD2 | 192.168.0.6 | Production Server (Win Server 2008 R2) | INTRANET\sysadmin / Paper123!@# |
|
||||
| D2TESTNAS | 192.168.0.9 | TrueNAS, SMB1 proxy for DOS machines | root / (SSH key) or admin / Paper123!@#-nas |
|
||||
| DOS Stations | 192.168.0.x | ~30 DOS 6.22 test machines (TS-XX) | N/A |
|
||||
| UDM Gateway | 192.168.0.254 | UniFi Dream Machine | N/A |
|
||||
|
||||
---
|
||||
|
||||
## What We Already Know About TestDataSheetUploader
|
||||
|
||||
This is a VB.NET console app (.NET Framework 4.7.2) last built November 2, 2022.
|
||||
|
||||
### What it does
|
||||
1. Calls `https://www.dataforth.com/Services/DirectoryManifest.aspx` to get a list of files already on the web server
|
||||
2. Compares local files against that manifest (by filename, size, and last-modified date)
|
||||
3. Uploads new/changed files via `https://www.dataforth.com/Services/Uploader.aspx`
|
||||
4. Deletes files from server that no longer exist locally via `https://www.dataforth.com/Services/DeleteFile.aspx`
|
||||
5. Only processes files modified in the current year
|
||||
|
||||
### Configured paths (from app.config)
|
||||
- **Service auth:** username=DataforthWebShare, password=Data6277
|
||||
- **TestDataSheetPath:** `C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists`
|
||||
- **TestFolderPath:** `C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists`
|
||||
- **InventoryDataStagingFolder:** `C:\TestDataSheetUploader\staging`
|
||||
- **InventoryDataSourceFolder:** `C:\TestDataSheetUploader\src`
|
||||
- **InventoryDataFiles:** AvSelCat.csv, AvSelCus.csv
|
||||
|
||||
### Server-side destination (from error logs)
|
||||
```
|
||||
C:\inetpub\wwwroot\dataforth.com\WebShare\ProcessCheckOutTestFolder\
|
||||
```
|
||||
|
||||
### Key unknowns -- what you need to find out
|
||||
- **Who is "hoffm"?** Likely a Hoffman who worked at Dataforth. Which machine was this?
|
||||
- **Where do test datasheets originate?** The DOS machines run QuickBASIC data acquisition. Do they produce datasheet files?
|
||||
- **Is there a path from DOS machines -> datasheets?** The DOS machines map `T:` to `\\D2TESTNAS\TEST`. Is there a datasheets share they write to?
|
||||
- **Is the uploader still running?** Scheduled task? Manual? Last used?
|
||||
- **Where does `C:\Users\hoffm\...` map to now?** Did someone take over this role?
|
||||
|
||||
---
|
||||
|
||||
## Investigation Steps
|
||||
|
||||
### On AD1 (this machine)
|
||||
```powershell
|
||||
# Check if TestDataSheetUploader exists anywhere on this machine
|
||||
Get-ChildItem -Path C:\ -Recurse -Filter "TestDataSheetUploader*" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check for Hoffman's profile or traces
|
||||
Get-ChildItem C:\Users\ -Directory
|
||||
Get-ChildItem "C:\Users\hoffm" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check scheduled tasks for anything datasheet-related
|
||||
Get-ScheduledTask | Where-Object { $_.TaskName -like "*data*" -or $_.TaskName -like "*sheet*" -or $_.TaskName -like "*upload*" -or $_.TaskName -like "*sync*" }
|
||||
|
||||
# Check for IIS sites (AD1 might host www.dataforth.com)
|
||||
Import-Module WebAdministration -ErrorAction SilentlyContinue
|
||||
Get-Website -ErrorAction SilentlyContinue
|
||||
Get-ChildItem "C:\inetpub\wwwroot" -ErrorAction SilentlyContinue
|
||||
```
|
||||
|
||||
### On AD2 (192.168.0.6)
|
||||
```powershell
|
||||
# Remote into AD2 and check
|
||||
Invoke-Command -ComputerName 192.168.0.6 -Credential (Get-Credential INTRANET\sysadmin) -ScriptBlock {
|
||||
# Check for the uploader
|
||||
Get-ChildItem -Path C:\ -Recurse -Filter "TestDataSheetUploader*" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check IIS
|
||||
Get-ChildItem "C:\inetpub\wwwroot" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check for the WebShare path from error logs
|
||||
Get-ChildItem "C:\inetpub\wwwroot\dataforth.com\WebShare" -ErrorAction SilentlyContinue
|
||||
|
||||
# Check scheduled tasks
|
||||
Get-ScheduledTask | Where-Object { $_.TaskName -like "*data*" -or $_.TaskName -like "*upload*" }
|
||||
|
||||
# Check user profiles
|
||||
Get-ChildItem C:\Users\ -Directory
|
||||
}
|
||||
```
|
||||
|
||||
### On D2TESTNAS (192.168.0.9)
|
||||
```bash
|
||||
# SSH from AD1 or any machine with access
|
||||
ssh root@192.168.0.9
|
||||
|
||||
# Check datasheets share
|
||||
ls -la /data/datasheets/
|
||||
find /data/ -name "*datasheet*" -o -name "*TestData*" 2>/dev/null
|
||||
|
||||
# Check if DOS machines write any test output files
|
||||
ls -la /data/test/TS-27/
|
||||
find /data/test/ -name "*.pdf" -o -name "*.csv" -o -name "*.dat" 2>/dev/null
|
||||
```
|
||||
|
||||
### Check the Dataforth website services
|
||||
```powershell
|
||||
# Test if the manifest service still responds
|
||||
$cred = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("DataforthWebShare:Data6277"))
|
||||
Invoke-WebRequest -Uri "https://www.dataforth.com/Services/DirectoryManifest.aspx" -Headers @{Authorization="Basic $cred"} -Method GET -ErrorAction SilentlyContinue
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DOS Test Machine Architecture (Full Context)
|
||||
|
||||
The DOS machines are ~30 stations running DOS 6.22 with QuickBASIC 4.5 data acquisition software.
|
||||
|
||||
```
|
||||
DOS Machines (TS-XX) --SMB1--> D2TESTNAS (192.168.0.9) --SMB2/rsync--> AD2 (192.168.0.6)
|
||||
| /data/test/ C:\Shares\test\
|
||||
| /data/datasheets/ C:\Shares\datasheets (PENDING)
|
||||
|
|
||||
+-- Map T: = \\D2TESTNAS\TEST
|
||||
+-- Run QuickBASIC data acquisition
|
||||
+-- UPDATE.BAT for remote management
|
||||
+-- TODO.BAT for remote task execution
|
||||
```
|
||||
|
||||
**Bidirectional sync** runs every 15 minutes between D2TESTNAS and AD2 via `/root/sync-to-ad2.sh`.
|
||||
|
||||
The datasheets share (`\\D2TESTNAS\datasheets` -> `/data/datasheets/`) exists on D2TESTNAS but the corresponding AD2 share (`\\AD2\datasheets`) was never created -- it's listed as a remaining task. This may be relevant to the test datasheet pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Where to Save Your Findings
|
||||
|
||||
Write your investigation results to:
|
||||
```
|
||||
clients/dataforth/dos-test-machines/Test Datasheets/INVESTIGATION.md
|
||||
```
|
||||
|
||||
Include:
|
||||
- What you found on each machine
|
||||
- The complete datasheet pipeline (or what's missing/broken)
|
||||
- Whether the uploader is still active
|
||||
- Recommendations for what to do next
|
||||
|
||||
Then commit and push to Gitea using the credentials above.
|
||||
|
||||
---
|
||||
|
||||
## Contact
|
||||
|
||||
- **AJ at Dataforth** -- engineering contact, can answer questions about the test workflow
|
||||
- **Coordinator instance** -- will see your findings after you push to Gitea
|
||||
BIN
Test Datasheets/SpecData/5BMAIN.DAT
Normal file
BIN
Test Datasheets/SpecData/5BMAIN.DAT
Normal file
Binary file not shown.
BIN
Test Datasheets/SpecData/8BMAIN.DAT
Normal file
BIN
Test Datasheets/SpecData/8BMAIN.DAT
Normal file
Binary file not shown.
BIN
Test Datasheets/SpecData/DSCOUT.DAT
Normal file
BIN
Test Datasheets/SpecData/DSCOUT.DAT
Normal file
Binary file not shown.
BIN
Test Datasheets/SpecData/SCTMAIN.DAT
Normal file
BIN
Test Datasheets/SpecData/SCTMAIN.DAT
Normal file
Binary file not shown.
BIN
Test Datasheets/TestDataSheetUploader.zip
Normal file
BIN
Test Datasheets/TestDataSheetUploader.zip
Normal file
Binary file not shown.
158
Test Datasheets/TestDataSheetUploader/HTTPUploader.vb
Normal file
158
Test Datasheets/TestDataSheetUploader/HTTPUploader.vb
Normal file
@@ -0,0 +1,158 @@
|
||||
Imports System.Text
|
||||
Imports System.Net
|
||||
Imports System.IO
|
||||
|
||||
Public Class HTTPUploader
|
||||
|
||||
|
||||
|
||||
Public Shared Function UploadFile(ByVal url As String, ByVal credentials As Net.NetworkCredential, ByVal localPathFilename As String, ByVal nvc As System.Collections.Specialized.NameValueCollection, ByRef LogMessage As String) As Boolean
|
||||
Try
|
||||
'Return True
|
||||
Dim length As Long = 0
|
||||
'Dim boundary As String = "----------------------------" & Date.Now.Ticks.ToString("x")
|
||||
Dim boundary As String = "----------------------------061366199019971999"
|
||||
|
||||
Dim httpWebRequest2 As HttpWebRequest = WebRequest.Create(url)
|
||||
httpWebRequest2.ContentType = "multipart/form-data; boundary=" & boundary
|
||||
httpWebRequest2.Method = "POST"
|
||||
httpWebRequest2.KeepAlive = True
|
||||
httpWebRequest2.Credentials = credentials
|
||||
httpWebRequest2.Timeout = 900000
|
||||
|
||||
|
||||
Dim memStream As New System.IO.MemoryStream()
|
||||
|
||||
Dim boundarybytes() As Byte = System.Text.Encoding.ASCII.GetBytes(vbCrLf & "--" & boundary & vbCrLf)
|
||||
|
||||
|
||||
Dim formdataTemplate As String = vbCrLf & "--" + boundary & vbCrLf & "Content-Disposition: form-data; name=""{0}"";" & vbCrLf & vbCrLf & "{1}"
|
||||
|
||||
For Each key As String In nvc.Keys
|
||||
Dim formitem As String = String.Format(formdataTemplate, key, nvc(key))
|
||||
Dim formitembytes() As Byte = System.Text.Encoding.UTF8.GetBytes(formitem)
|
||||
memStream.Write(formitembytes, 0, formitembytes.Length)
|
||||
Next
|
||||
|
||||
|
||||
memStream.Write(boundarybytes, 0, boundarybytes.Length)
|
||||
|
||||
Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}"" " & _
|
||||
"Content-Type: application/octet-stream" & vbCrLf & vbCrLf
|
||||
|
||||
'Content-Type: application/octet-stream
|
||||
|
||||
|
||||
'string header = string.Format(headerTemplate, "file" + i, files[i]);
|
||||
Dim header As String = String.Format(headerTemplate, "file1", localPathFilename)
|
||||
|
||||
Dim headerbytes() As Byte = System.Text.Encoding.UTF8.GetBytes(header)
|
||||
|
||||
memStream.Write(headerbytes, 0, headerbytes.Length)
|
||||
|
||||
|
||||
|
||||
Dim byteArray As Byte() = File.ReadAllBytes(localPathFilename)
|
||||
memStream.Write(byteArray, 0, byteArray.Length)
|
||||
|
||||
memStream.Write(boundarybytes, 0, boundarybytes.Length)
|
||||
|
||||
|
||||
|
||||
httpWebRequest2.ContentLength = memStream.Length + 1
|
||||
|
||||
Dim requestStream As Stream = httpWebRequest2.GetRequestStream()
|
||||
|
||||
memStream.Position = 0
|
||||
Dim tempBuffer(memStream.Length) As Byte
|
||||
memStream.Read(tempBuffer, 0, tempBuffer.Length)
|
||||
memStream.Close()
|
||||
requestStream.Write(tempBuffer, 0, tempBuffer.Length)
|
||||
requestStream.Close()
|
||||
|
||||
Dim webResponse2 As WebResponse = httpWebRequest2.GetResponse()
|
||||
|
||||
Dim stream2 As Stream = webResponse2.GetResponseStream()
|
||||
Dim reader2 As New StreamReader(stream2)
|
||||
|
||||
Dim xmlResponse As String = reader2.ReadToEnd
|
||||
|
||||
webResponse2.Close()
|
||||
httpWebRequest2 = Nothing
|
||||
webResponse2 = Nothing
|
||||
|
||||
|
||||
Dim ds As New DataSet
|
||||
ds.ReadXml(New System.Xml.XmlTextReader(New StringReader(xmlResponse)))
|
||||
|
||||
Dim responseMessage As String = ds.Tables("Result").Rows(0)("Message")
|
||||
If responseMessage = "SUCCESS" Then
|
||||
Dim uploadedFilesize As Long = ds.Tables("Result").Rows(0)("SavedFileSize")
|
||||
If My.Computer.FileSystem.GetFileInfo(localPathFilename).Length = uploadedFilesize Then
|
||||
'we are done
|
||||
Return True
|
||||
Else
|
||||
LogMessage = "Uploaded filesize (" & uploadedFilesize & ") does not match local filesize (" & My.Computer.FileSystem.GetFileInfo(localPathFilename).Length & ")"
|
||||
End If
|
||||
Else
|
||||
LogMessage = "Dataforth Service Upload Error: " & ds.Tables("Result").Rows(0)("ErrorMessage")
|
||||
End If
|
||||
Return False
|
||||
Catch ex As Exception
|
||||
LogMessage = "Exception while uploading to Dataforth Service: " & ex.ToString
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
'Public Shared Sub _UploadVideo_(ByVal url As String, ByVal credentials As Net.NetworkCredential, ByVal localPathFilename As String, ByVal nvc As System.Collections.Specialized.NameValueCollection)
|
||||
' Try
|
||||
' Dim client As New WebClient
|
||||
' client.Credentials = credentials
|
||||
' Dim bogus As Integer = -1
|
||||
' Dim requestURL As String = url & "?ecsId=" & nvc.Get("ecsId")
|
||||
' 'requestURL = requestURL.Replace("https://", "http://")
|
||||
|
||||
' Dim response() As Byte = client.UploadFile(requestURL, localPathFilename)
|
||||
' MsgBox(System.Text.Encoding.Unicode.GetString(response))
|
||||
' Catch webEx As WebException
|
||||
' Dim thisE As String = webEx.ToString
|
||||
|
||||
' Catch ex As Exception
|
||||
|
||||
' End Try
|
||||
'End Sub
|
||||
|
||||
|
||||
'Public Shared Sub UploadVideo__(ByVal url As String, ByVal credentials As Net.NetworkCredential, ByVal localPathFilename As String, ByVal nvc As System.Collections.Specialized.NameValueCollection)
|
||||
|
||||
' Dim requestURL As String = url
|
||||
' Dim boundary As String = "----------------------------" & Date.Now.Ticks.ToString("x")
|
||||
|
||||
' 'Create Request
|
||||
' Dim webRequest As System.Net.HttpWebRequest = CType(System.Net.WebRequest.Create(requestURL), System.Net.HttpWebRequest)
|
||||
' webRequest.Credentials = credentials
|
||||
' webRequest.Timeout = 120000
|
||||
' 'System.Net.ServicePointManager.ServerCertificateValidationCallback = (Function(sender, certificate, chain, sslPolicyErrors) True)
|
||||
' 'webRequest.ContentType = "application/x-www-form-urlencoded"
|
||||
' webRequest.ContentType = "multipart/form-data; boundary=" & boundary
|
||||
' webRequest.Method = "POST"
|
||||
|
||||
|
||||
' Dim byteArray As Byte() = File.ReadAllBytes(localPathFilename)
|
||||
' webRequest.ContentLength = byteArray.Length
|
||||
' Dim dataStream As Stream = webRequest.GetRequestStream
|
||||
' dataStream.Write(byteArray, 0, byteArray.Length)
|
||||
' dataStream.Close()
|
||||
|
||||
|
||||
' ' Retrieve data from Response
|
||||
' Dim webResponse As System.Net.HttpWebResponse = CType(webRequest.GetResponse(), System.Net.HttpWebResponse)
|
||||
' Dim sr As New System.IO.StreamReader(webResponse.GetResponseStream(), System.Text.Encoding.UTF8)
|
||||
' Dim responseString As String = sr.ReadToEnd()
|
||||
' MsgBox(responseString)
|
||||
|
||||
'End Sub
|
||||
|
||||
End Class
|
||||
264
Test Datasheets/TestDataSheetUploader/Module1.vb
Normal file
264
Test Datasheets/TestDataSheetUploader/Module1.vb
Normal file
@@ -0,0 +1,264 @@
|
||||
Module Module1
|
||||
|
||||
Private processLog As System.Text.StringBuilder
|
||||
|
||||
Sub Main()
|
||||
processLog = New System.Text.StringBuilder()
|
||||
Dim appSettings As New Configuration.AppSettingsReader
|
||||
|
||||
|
||||
'for testing only
|
||||
'UploadFilesInDirectory("C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists", "TestFolder")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
'CopyInventoryFilesToStagingFolder()
|
||||
'SyncFolder("InventoryDataFolder")
|
||||
|
||||
SyncFolder("TestDataSheet")
|
||||
|
||||
|
||||
Dim logFilename As String = My.Application.Info.DirectoryPath & "\processLog." & Now.ToString("yyyy.MM.dd.HH.mm.ss") & ".txt"
|
||||
My.Computer.FileSystem.WriteAllText(logFilename, processLog.ToString, False)
|
||||
|
||||
|
||||
End Sub
|
||||
|
||||
Private Sub AddToLog(ByVal message As String, ByVal Echo As Boolean)
|
||||
processLog.Append(Now.ToString("MM/dd/YYYY HH:mm:ss | ") & message & vbCrLf)
|
||||
If Echo Then
|
||||
Console.WriteLine(message)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
|
||||
Public Sub CopyInventoryFilesToStagingFolder()
|
||||
|
||||
Dim appSettings As New Configuration.AppSettingsReader
|
||||
Dim stagingFolderPath As String = appSettings.GetValue("InventoryDataStagingFolder", GetType(String))
|
||||
Dim srcFolderPath As String = appSettings.GetValue("InventoryDataSourceFolder", GetType(String))
|
||||
Dim filenamesStr As String = appSettings.GetValue("InventoryDataFiles", GetType(String))
|
||||
|
||||
Dim filenames() As String = filenamesStr.Split(",")
|
||||
|
||||
For Each thisFilename As String In filenames
|
||||
Dim src As String = srcFolderPath & "\" & thisFilename
|
||||
Dim dest As String = stagingFolderPath & "\" & thisFilename
|
||||
My.Computer.FileSystem.CopyFile(src, dest, True)
|
||||
Next
|
||||
|
||||
|
||||
End Sub
|
||||
|
||||
|
||||
Public Sub UploadFilesInDirectory(ByVal DirectoryPath As String, ByVal UploadType As String)
|
||||
|
||||
|
||||
|
||||
Dim appSettings As New Configuration.AppSettingsReader
|
||||
Dim username As String = appSettings.GetValue("ServiceUsername", GetType(String))
|
||||
Dim password As String = appSettings.GetValue("ServicePassword", GetType(String))
|
||||
Dim serviceCredentials As New Net.NetworkCredential(username, password)
|
||||
Dim url As String = appSettings.GetValue("UploaderServiceURL", GetType(String))
|
||||
|
||||
|
||||
|
||||
For Each thisFile As String In My.Computer.FileSystem.GetFiles(DirectoryPath)
|
||||
|
||||
Dim formParameters As New System.Collections.Specialized.NameValueCollection
|
||||
formParameters.Add("UploadType", UploadType)
|
||||
|
||||
Dim logMessage As New String("")
|
||||
Console.WriteLine("Uploading: " & thisFile)
|
||||
If HTTPUploader.UploadFile(url, serviceCredentials, thisFile, formParameters, logMessage) Then
|
||||
'this video is now staged
|
||||
AddToLog("Uploaded " & thisFile, True)
|
||||
|
||||
My.Computer.FileSystem.DeleteFile(thisFile)
|
||||
Else
|
||||
|
||||
AddToLog("Upload FAILED for " & thisFile, True)
|
||||
AddToLog("Upload FAIL MESSAGE: " & logMessage, False)
|
||||
Console.WriteLine("ERROR: " & logMessage)
|
||||
End If
|
||||
|
||||
|
||||
Next
|
||||
|
||||
|
||||
End Sub
|
||||
|
||||
Public Sub SyncFolder(ByVal FolderAlias As String)
|
||||
Try
|
||||
AddToLog("SyncFolder(" & FolderAlias & ") started.", True)
|
||||
'get manifest of files that are on server mirror
|
||||
Dim appSettings As New Configuration.AppSettingsReader
|
||||
Dim username As String = appSettings.GetValue("ServiceUsername", GetType(String))
|
||||
Dim password As String = appSettings.GetValue("ServicePassword", GetType(String))
|
||||
Dim serviceCredentials As New Net.NetworkCredential(username, password)
|
||||
Dim manifestServiceUrl As String = appSettings.GetValue("DirectoryManifestServiceURL", GetType(String))
|
||||
Dim uploadServiceUrl As String = appSettings.GetValue("UploaderServiceURL", GetType(String))
|
||||
Dim deleteServiceUrl As String = appSettings.GetValue("DeleteFileServiceURL", GetType(String))
|
||||
Dim testMode As Boolean = appSettings.GetValue("TestMode", GetType(Boolean))
|
||||
|
||||
'Create an XML file to post with the request
|
||||
Dim requestDS As New DataSet("Request")
|
||||
Dim requestDT As New DataTable("RequestData")
|
||||
requestDT.Columns.Add("SyncPathAlias", GetType(String))
|
||||
requestDS.Tables.Add(requestDT)
|
||||
Dim requestDR As DataRow = requestDT.NewRow
|
||||
requestDR("SyncPathAlias") = FolderAlias
|
||||
requestDT.Rows.Add(requestDR)
|
||||
|
||||
'Get Dataset from XML response
|
||||
Dim manifestXML As String = CSFramework_Utilities.XMLData.DownloadXMLWithDatasetPost(manifestServiceUrl, requestDS, serviceCredentials)
|
||||
|
||||
My.Computer.FileSystem.WriteAllText(My.Application.Info.DirectoryPath & "\manifest.xml", manifestXML, False)
|
||||
|
||||
Dim ds As DataSet = CSFramework_Utilities.XMLData.DatasetFromXML(manifestXML)
|
||||
|
||||
AddToLog("Manifest downloaded with " & ds.Tables("ContentFile").Rows.Count & " files.", True)
|
||||
|
||||
'Build a list of files that should be uploaded
|
||||
Dim filesToUpload As New List(Of String)
|
||||
|
||||
Dim localFolderPath As String = ""
|
||||
Select Case FolderAlias
|
||||
Case "TestDataSheet"
|
||||
localFolderPath = appSettings.GetValue("TestDataSheetPath", GetType(String))
|
||||
Case "TestFolder"
|
||||
localFolderPath = appSettings.GetValue("TestFolderPath", GetType(String))
|
||||
Case "InventoryDataFolder"
|
||||
localFolderPath = appSettings.GetValue("InventoryDataStagingFolder", GetType(String))
|
||||
End Select
|
||||
|
||||
Dim discoveryFileCount As Integer = 0
|
||||
Dim discoveryFileEchoCount As Integer = 1000
|
||||
|
||||
Dim sourceFolder As New System.IO.DirectoryInfo(localFolderPath)
|
||||
AddToLog("Accessing local folder: " & localFolderPath, True)
|
||||
|
||||
For Each thisLocalFileInfo As System.IO.FileInfo In sourceFolder.GetFiles
|
||||
discoveryFileCount += 1
|
||||
If discoveryFileCount = 1 Then
|
||||
AddToLog("Found at least 1 file in local folder", True)
|
||||
End If
|
||||
If discoveryFileCount = discoveryFileEchoCount Then
|
||||
AddToLog("Discovery file count: " & discoveryFileEchoCount, True)
|
||||
discoveryFileEchoCount += 1000
|
||||
End If
|
||||
'Dim thisLocalFileInfo As New System.IO.FileInfo(thisLocalFile)
|
||||
|
||||
|
||||
If thisLocalFileInfo.LastWriteTimeUtc.Year = Now.Year Then
|
||||
Dim foundMatchingFileOnServer As Boolean = False
|
||||
If ds.Tables.Contains("ContentFile") Then
|
||||
For Each dr As DataRow In ds.Tables("ContentFile").Rows
|
||||
If dr("Filename").ToString = thisLocalFileInfo.Name Then
|
||||
Dim filesize As Integer = dr("Filesize")
|
||||
Dim datelastupdated As Date = dr("DateLastUpdated")
|
||||
datelastupdated = datelastupdated.ToUniversalTime
|
||||
If filesize = thisLocalFileInfo.Length Then
|
||||
If thisLocalFileInfo.LastWriteTimeUtc.ToString("yyyy.MM.dd.HH.mm.ss") = datelastupdated.ToString("yyyy.MM.dd.HH.mm.ss") Then
|
||||
foundMatchingFileOnServer = True
|
||||
Exit For
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
If Not foundMatchingFileOnServer Then
|
||||
filesToUpload.Add(thisLocalFileInfo.FullName)
|
||||
AddToLog("Requesting upload: " & thisLocalFileInfo.Name, True)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
|
||||
AddToLog("Found " & filesToUpload.Count & " files that need to be uploaded.", True)
|
||||
|
||||
'Upload Files to Server
|
||||
If Not testMode Then
|
||||
For Each thisFile As String In filesToUpload
|
||||
Dim thisLocalFileInfo As New System.IO.FileInfo(thisFile)
|
||||
Dim formParameters As New System.Collections.Specialized.NameValueCollection
|
||||
formParameters.Add("UploadType", FolderAlias)
|
||||
'Request("LastUpdatedDate")
|
||||
formParameters.Add("LastUpdatedDate", thisLocalFileInfo.LastWriteTimeUtc.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"))
|
||||
'2015-12-11T17:38:05.9190462Z
|
||||
|
||||
Dim logMessage As New String("")
|
||||
Console.WriteLine("Uploading: " & thisFile)
|
||||
If HTTPUploader.UploadFile(uploadServiceUrl, serviceCredentials, thisFile, formParameters, logMessage) Then
|
||||
'this file is now staged
|
||||
AddToLog("Uploaded file: " & thisFile, True)
|
||||
|
||||
'My.Computer.FileSystem.DeleteFile(thisFile)
|
||||
Else
|
||||
|
||||
AddToLog("Upload FAILED for " & thisFile, True)
|
||||
AddToLog("Upload FAIL MESSAGE: " & logMessage, False)
|
||||
Console.WriteLine("ERROR: " & logMessage)
|
||||
End If
|
||||
|
||||
|
||||
Next
|
||||
End If
|
||||
|
||||
|
||||
'Create dataset for DeleteFile service
|
||||
Dim deleteDS As New DataSet("DeleteRequestData")
|
||||
|
||||
|
||||
'add request data
|
||||
Dim deleteRD As New DataTable("RequestData")
|
||||
deleteRD.Columns.Add("SyncPathAlias", GetType(String))
|
||||
Dim deleteDataDR As DataRow = deleteRD.NewRow
|
||||
deleteDataDR("SyncPathAlias") = FolderAlias
|
||||
deleteRD.Rows.Add(deleteDataDR)
|
||||
deleteDS.Tables.Add(deleteRD)
|
||||
|
||||
|
||||
'add filenames
|
||||
Dim deleteDT As New DataTable("Filenames")
|
||||
deleteDT.Columns.Add("Filename", GetType(String))
|
||||
deleteDS.Tables.Add(deleteDT)
|
||||
|
||||
If ds.Tables.Contains("ContentFile") Then
|
||||
For Each dr As DataRow In ds.Tables("ContentFile").Rows
|
||||
Dim localFileName As String = localFolderPath & "\" & dr("Filename").ToString
|
||||
If Not My.Computer.FileSystem.FileExists(localFileName) Then
|
||||
|
||||
Dim deleteDR As DataRow = deleteDT.NewRow
|
||||
deleteDR("Filename") = dr("Filename").ToString
|
||||
deleteDT.Rows.Add(deleteDR)
|
||||
|
||||
AddToLog("Requested " & FolderAlias & " Delete: " & dr("Filename").ToString, True)
|
||||
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
|
||||
AddToLog("Found " & deleteDT.Rows.Count & " files to delete.", True)
|
||||
|
||||
|
||||
'Delete obsolete files that were detected
|
||||
If Not testMode Then
|
||||
If deleteDT.Rows.Count > 0 Then
|
||||
Dim deleteResponseXML As String = CSFramework_Utilities.XMLData.DownloadXMLWithDatasetPost(deleteServiceUrl, deleteDS, serviceCredentials)
|
||||
AddToLog("Obsolete " & FolderAlias & " files deleted.", True)
|
||||
Else
|
||||
AddToLog("No obsolete " & FolderAlias & " files were detected.", True)
|
||||
End If
|
||||
End If
|
||||
|
||||
Catch ex As Exception
|
||||
AddToLog("Exception in SyncFolder: " & ex.ToString, True)
|
||||
|
||||
|
||||
End Try
|
||||
End Sub
|
||||
|
||||
|
||||
End Module
|
||||
13
Test Datasheets/TestDataSheetUploader/My Project/Application.Designer.vb
generated
Normal file
13
Test Datasheets/TestDataSheetUploader/My Project/Application.Designer.vb
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<MySubMain>false</MySubMain>
|
||||
<SingleInstance>false</SingleInstance>
|
||||
<ShutdownMode>0</ShutdownMode>
|
||||
<EnableVisualStyles>true</EnableVisualStyles>
|
||||
<AuthenticationMode>0</AuthenticationMode>
|
||||
<ApplicationType>2</ApplicationType>
|
||||
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||
</MyApplicationData>
|
||||
@@ -0,0 +1,35 @@
|
||||
Imports System
|
||||
Imports System.Reflection
|
||||
Imports System.Runtime.InteropServices
|
||||
|
||||
' General Information about an assembly is controlled through the following
|
||||
' set of attributes. Change these attribute values to modify the information
|
||||
' associated with an assembly.
|
||||
|
||||
' Review the values of the assembly attributes
|
||||
|
||||
<Assembly: AssemblyTitle("TestDataSheetUploader")>
|
||||
<Assembly: AssemblyDescription("")>
|
||||
<Assembly: AssemblyCompany("Hewlett-Packard")>
|
||||
<Assembly: AssemblyProduct("TestDataSheetUploader")>
|
||||
<Assembly: AssemblyCopyright("Copyright © Hewlett-Packard 2016")>
|
||||
<Assembly: AssemblyTrademark("")>
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
'The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
<Assembly: Guid("7fe555fe-f768-41e5-b89d-89289692ba0e")>
|
||||
|
||||
' Version information for an assembly consists of the following four values:
|
||||
'
|
||||
' Major Version
|
||||
' Minor Version
|
||||
' Build Number
|
||||
' Revision
|
||||
'
|
||||
' You can specify all the values or you can default the Build and Revision Numbers
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("1.0.0.0")>
|
||||
<Assembly: AssemblyFileVersion("1.0.0.0")>
|
||||
63
Test Datasheets/TestDataSheetUploader/My Project/Resources.Designer.vb
generated
Normal file
63
Test Datasheets/TestDataSheetUploader/My Project/Resources.Designer.vb
generated
Normal file
@@ -0,0 +1,63 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
Imports System
|
||||
|
||||
Namespace My.Resources
|
||||
|
||||
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
'class via a tool like ResGen or Visual Studio.
|
||||
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
'with the /str option, or rebuild your VS project.
|
||||
'''<summary>
|
||||
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||
'''</summary>
|
||||
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0"), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||
Friend Module Resources
|
||||
|
||||
Private resourceMan As Global.System.Resources.ResourceManager
|
||||
|
||||
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||
|
||||
'''<summary>
|
||||
''' Returns the cached ResourceManager instance used by this class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||
Get
|
||||
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("TestDataSheetUploader.Resources", GetType(Resources).Assembly)
|
||||
resourceMan = temp
|
||||
End If
|
||||
Return resourceMan
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Overrides the current thread's CurrentUICulture property for all
|
||||
''' resource lookups using this strongly typed resource class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||
Get
|
||||
Return resourceCulture
|
||||
End Get
|
||||
Set
|
||||
resourceCulture = value
|
||||
End Set
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
117
Test Datasheets/TestDataSheetUploader/My Project/Resources.resx
Normal file
117
Test Datasheets/TestDataSheetUploader/My Project/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
73
Test Datasheets/TestDataSheetUploader/My Project/Settings.Designer.vb
generated
Normal file
73
Test Datasheets/TestDataSheetUploader/My Project/Settings.Designer.vb
generated
Normal file
@@ -0,0 +1,73 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.42000
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0"), _
|
||||
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Partial Friend NotInheritable Class MySettings
|
||||
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||
|
||||
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
|
||||
|
||||
#Region "My.Settings Auto-Save Functionality"
|
||||
#If _MyType = "WindowsForms" Then
|
||||
Private Shared addedHandler As Boolean
|
||||
|
||||
Private Shared addedHandlerLockObject As New Object
|
||||
|
||||
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
|
||||
If My.Application.SaveMySettingsOnExit Then
|
||||
My.Settings.Save()
|
||||
End If
|
||||
End Sub
|
||||
#End If
|
||||
#End Region
|
||||
|
||||
Public Shared ReadOnly Property [Default]() As MySettings
|
||||
Get
|
||||
|
||||
#If _MyType = "WindowsForms" Then
|
||||
If Not addedHandler Then
|
||||
SyncLock addedHandlerLockObject
|
||||
If Not addedHandler Then
|
||||
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||
addedHandler = True
|
||||
End If
|
||||
End SyncLock
|
||||
End If
|
||||
#End If
|
||||
Return defaultInstance
|
||||
End Get
|
||||
End Property
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||
Friend Module MySettingsProperty
|
||||
|
||||
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||
Friend ReadOnly Property Settings() As Global.TestDataSheetUploader.My.MySettings
|
||||
Get
|
||||
Return Global.TestDataSheetUploader.My.MySettings.Default
|
||||
End Get
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "TestDataSheetUploader", "TestDataSheetUploader\TestDataSheetUploader.vbproj", "{78941EA8-4EF5-4194-99CD-A08CBB7B52FB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{78941EA8-4EF5-4194-99CD-A08CBB7B52FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{78941EA8-4EF5-4194-99CD-A08CBB7B52FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{78941EA8-4EF5-4194-99CD-A08CBB7B52FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{78941EA8-4EF5-4194-99CD-A08CBB7B52FB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{78941EA8-4EF5-4194-99CD-A08CBB7B52FB}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<StartupObject>TestDataSheetUploader.Module1</StartupObject>
|
||||
<RootNamespace>TestDataSheetUploader</RootNamespace>
|
||||
<AssemblyName>TestDataSheetUploader</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<MyType>Console</MyType>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DocumentationFile>TestDataSheetUploader.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DocumentationFile>TestDataSheetUploader.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionExplicit>On</OptionExplicit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionCompare>Binary</OptionCompare>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionStrict>Off</OptionStrict>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionInfer>On</OptionInfer>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Import Include="Microsoft.VisualBasic" />
|
||||
<Import Include="System" />
|
||||
<Import Include="System.Collections" />
|
||||
<Import Include="System.Collections.Generic" />
|
||||
<Import Include="System.Data" />
|
||||
<Import Include="System.Diagnostics" />
|
||||
<Import Include="System.Linq" />
|
||||
<Import Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="HTTPUploader.vb" />
|
||||
<Compile Include="Module1.vb" />
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Application.myapp</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Resources.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Settings.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="XMLData.vb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="My Project\Resources.resx">
|
||||
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="My Project\Application.myapp">
|
||||
<Generator>MyApplicationCodeGenerator</Generator>
|
||||
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
<None Include="My Project\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<CustomToolNamespace>My</CustomToolNamespace>
|
||||
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
81
Test Datasheets/TestDataSheetUploader/XMLData.vb
Normal file
81
Test Datasheets/TestDataSheetUploader/XMLData.vb
Normal file
@@ -0,0 +1,81 @@
|
||||
Imports System.Xml
|
||||
Imports System.Net
|
||||
Imports System.IO
|
||||
|
||||
Namespace CSFramework_Utilities
|
||||
|
||||
Public Class XMLData
|
||||
|
||||
Public Shared Function XMLStringFromDataset(ByVal ds As DataSet) As String
|
||||
Dim sw As New StringWriter()
|
||||
ds.WriteXml(sw, XmlWriteMode.IgnoreSchema)
|
||||
Return sw.ToString()
|
||||
End Function
|
||||
|
||||
Public Shared Function DownloadXMLAsDataset(ByVal url As String, Optional ByVal credentials As Net.NetworkCredential = Nothing) As DataSet
|
||||
|
||||
Dim myXMLReader As XmlReader
|
||||
Dim myDataSet As New DataSet
|
||||
If credentials IsNot Nothing Then
|
||||
Dim myXMLResolver As XmlUrlResolver = New XmlUrlResolver
|
||||
myXMLResolver.Credentials = credentials
|
||||
Dim myXMLSettings As XmlReaderSettings = New XmlReaderSettings
|
||||
myXMLSettings.XmlResolver = myXMLResolver
|
||||
myXMLReader = XmlReader.Create(url, myXMLSettings)
|
||||
Else
|
||||
myXMLReader = XmlReader.Create(url)
|
||||
End If
|
||||
myDataSet.ReadXml(myXMLReader)
|
||||
Return myDataSet
|
||||
End Function
|
||||
|
||||
|
||||
Public Shared Function DownloadXMLWithDatasetPost(ByVal url As String, ByVal datasetToPost As DataSet, ByVal credentials As System.Net.NetworkCredential) As String
|
||||
|
||||
|
||||
Dim xmlrequest As HttpWebRequest = WebRequest.Create(url)
|
||||
xmlrequest.ContentType = "text/xml"
|
||||
xmlrequest.Method = WebRequestMethods.Http.Post
|
||||
xmlrequest.Credentials = credentials
|
||||
xmlrequest.Timeout = 2000000
|
||||
Try
|
||||
|
||||
Dim newStream As Stream = xmlrequest.GetRequestStream()
|
||||
datasetToPost.WriteXml(newStream)
|
||||
newStream.Close()
|
||||
|
||||
Dim xmlresponse As WebResponse = xmlrequest.GetResponse()
|
||||
Dim responseStr As String = ConvertStreamToString(xmlresponse.GetResponseStream)
|
||||
|
||||
|
||||
Return responseStr
|
||||
|
||||
Catch ex As Exception
|
||||
Return "DownloadXMLWithDatasetPost ERROR: " & vbCrLf & ex.ToString
|
||||
End Try
|
||||
|
||||
End Function
|
||||
|
||||
Public Shared Function ConvertStreamToString(ByVal InputStream As System.IO.Stream) As String
|
||||
Dim sr As System.IO.StreamReader = New System.IO.StreamReader(InputStream)
|
||||
Dim responseStr As String = sr.ReadToEnd()
|
||||
Return responseStr
|
||||
End Function
|
||||
|
||||
Public Shared Function DatasetFromXML(ByVal xml As String) As DataSet
|
||||
|
||||
Dim dataSet As DataSet = New DataSet
|
||||
|
||||
|
||||
Dim xmlSR As System.IO.StringReader = New System.IO.StringReader(xml)
|
||||
|
||||
dataSet.ReadXml(xmlSR)
|
||||
|
||||
Return dataSet
|
||||
|
||||
End Function
|
||||
|
||||
|
||||
End Class
|
||||
|
||||
End Namespace
|
||||
40
Test Datasheets/TestDataSheetUploader/app.config
Normal file
40
Test Datasheets/TestDataSheetUploader/app.config
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="UploaderServiceURL" value="https://www.dataforth.com/Services/Uploader.aspx"/>
|
||||
<add key="DirectoryManifestServiceURL" value="https://www.dataforth.com/Services/DirectoryManifest.aspx"/>
|
||||
<add key="DeleteFileServiceURL" value="https://www.dataforth.com/Services/DeleteFile.aspx"/>
|
||||
<add key="ServiceUsername" value="DataforthWebShare"/>
|
||||
<add key="ServicePassword" value="Data6277"/>
|
||||
|
||||
<add key="TestDataSheetPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
<add key="TestFolderPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
|
||||
<add key="InventoryDataStagingFolder" value="C:\TestDataSheetUploader\staging"/>
|
||||
<add key="InventoryDataSourceFolder" value="C:\TestDataSheetUploader\src"/>
|
||||
<add key="InventoryDataFiles" value="AvSelCat.csv,AvSelCus.csv"/>
|
||||
|
||||
<add key="TestMode" value="false"/>
|
||||
|
||||
</appSettings>
|
||||
<system.diagnostics>
|
||||
<sources>
|
||||
<!-- This section defines the logging configuration for My.Application.Log -->
|
||||
<source name="DefaultSource" switchName="DefaultSwitch">
|
||||
<listeners>
|
||||
<add name="FileLog"/>
|
||||
<!-- Uncomment the below section to write to the Application Event Log -->
|
||||
<!--<add name="EventLog"/>-->
|
||||
</listeners>
|
||||
</source>
|
||||
</sources>
|
||||
<switches>
|
||||
<add name="DefaultSwitch" value="Information"/>
|
||||
</switches>
|
||||
<sharedListeners>
|
||||
<add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter"/>
|
||||
<!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
|
||||
<!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
|
||||
</sharedListeners>
|
||||
</system.diagnostics>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="UploaderServiceURL" value="https://www.dataforth.com/Services/Uploader.aspx"/>
|
||||
<add key="DirectoryManifestServiceURL" value="https://www.dataforth.com/Services/DirectoryManifest.aspx"/>
|
||||
<add key="DeleteFileServiceURL" value="https://www.dataforth.com/Services/DeleteFile.aspx"/>
|
||||
<add key="ServiceUsername" value="DataforthWebShare"/>
|
||||
<add key="ServicePassword" value="Data6277"/>
|
||||
|
||||
<add key="TestDataSheetPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
<add key="TestFolderPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
|
||||
<add key="InventoryDataStagingFolder" value="C:\TestDataSheetUploader\staging"/>
|
||||
<add key="InventoryDataSourceFolder" value="C:\TestDataSheetUploader\src"/>
|
||||
<add key="InventoryDataFiles" value="AvSelCat.csv,AvSelCus.csv"/>
|
||||
|
||||
<add key="TestMode" value="false"/>
|
||||
|
||||
</appSettings>
|
||||
<system.diagnostics>
|
||||
<sources>
|
||||
<!-- This section defines the logging configuration for My.Application.Log -->
|
||||
<source name="DefaultSource" switchName="DefaultSwitch">
|
||||
<listeners>
|
||||
<add name="FileLog"/>
|
||||
<!-- Uncomment the below section to write to the Application Event Log -->
|
||||
<!--<add name="EventLog"/>-->
|
||||
</listeners>
|
||||
</source>
|
||||
</sources>
|
||||
<switches>
|
||||
<add name="DefaultSwitch" value="Information"/>
|
||||
</switches>
|
||||
<sharedListeners>
|
||||
<add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter"/>
|
||||
<!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
|
||||
<!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
|
||||
</sharedListeners>
|
||||
</system.diagnostics>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
|
||||
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="UploaderServiceURL" value="https://www.dataforth.com/Services/Uploader.aspx"/>
|
||||
<add key="DirectoryManifestServiceURL" value="https://www.dataforth.com/Services/DirectoryManifest.aspx"/>
|
||||
<add key="DeleteFileServiceURL" value="https://www.dataforth.com/Services/DeleteFile.aspx"/>
|
||||
<add key="ServiceUsername" value="DataforthWebShare"/>
|
||||
<add key="ServicePassword" value="Data6277"/>
|
||||
|
||||
<add key="TestDataSheetPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
<add key="TestFolderPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
|
||||
<add key="InventoryDataStagingFolder" value="C:\TestDataSheetUploader\staging"/>
|
||||
<add key="InventoryDataSourceFolder" value="C:\TestDataSheetUploader\src"/>
|
||||
<add key="InventoryDataFiles" value="AvSelCat.csv,AvSelCus.csv"/>
|
||||
|
||||
<add key="TestMode" value="false"/>
|
||||
|
||||
</appSettings>
|
||||
<system.diagnostics>
|
||||
<sources>
|
||||
<!-- This section defines the logging configuration for My.Application.Log -->
|
||||
<source name="DefaultSource" switchName="DefaultSwitch">
|
||||
<listeners>
|
||||
<add name="FileLog"/>
|
||||
<!-- Uncomment the below section to write to the Application Event Log -->
|
||||
<!--<add name="EventLog"/>-->
|
||||
</listeners>
|
||||
</source>
|
||||
</sources>
|
||||
<switches>
|
||||
<add name="DefaultSwitch" value="Information"/>
|
||||
</switches>
|
||||
<sharedListeners>
|
||||
<add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter"/>
|
||||
<!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
|
||||
<!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
|
||||
</sharedListeners>
|
||||
</system.diagnostics>
|
||||
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>
|
||||
TestDataSheetUploader
|
||||
</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:TestDataSheetUploader.My.Resources.Resources">
|
||||
<summary>
|
||||
A strongly-typed resource class, for looking up localized strings, etc.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:TestDataSheetUploader.My.Resources.Resources.ResourceManager">
|
||||
<summary>
|
||||
Returns the cached ResourceManager instance used by this class.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:TestDataSheetUploader.My.Resources.Resources.Culture">
|
||||
<summary>
|
||||
Overrides the current thread's CurrentUICulture property for all
|
||||
resource lookups using this strongly typed resource class.
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
477923
Test Datasheets/TestDataSheetUploader/bin/Debug/manifest.xml
Normal file
477923
Test Datasheets/TestDataSheetUploader/bin/Debug/manifest.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
08/22/YYYY 15:47:17 | SyncFolder(TestFolder) started.
|
||||
08/22/YYYY 15:47:32 | Upload FAILED for C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists\Custom Product Listing.pdf
|
||||
08/22/YYYY 15:47:32 | Upload FAIL MESSAGE: GSSG Service Upload Error: UploadType not recognized: TestFolder
|
||||
08/22/YYYY 15:47:32 | Upload FAILED for C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists\Custom Product Rules.pdf
|
||||
08/22/YYYY 15:47:32 | Upload FAIL MESSAGE: GSSG Service Upload Error: UploadType not recognized: TestFolder
|
||||
08/22/YYYY 15:47:32 | No obsolete TestFolder files were detected.
|
||||
@@ -0,0 +1,6 @@
|
||||
08/22/YYYY 15:51:12 | SyncFolder(TestFolder) started.
|
||||
08/22/YYYY 15:51:15 | Upload FAILED for C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists\Custom Product Listing.pdf
|
||||
08/22/YYYY 15:51:15 | Upload FAIL MESSAGE: Dataforth Service Upload Error: Access to the path 'C:\inetpub\wwwroot\dataforth.com\WebShare\ProcessCheckOutTestFolder\Custom Product Listing.pdf' is denied.
|
||||
08/22/YYYY 15:51:15 | Upload FAILED for C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists\Custom Product Rules.pdf
|
||||
08/22/YYYY 15:51:15 | Upload FAIL MESSAGE: Dataforth Service Upload Error: Access to the path 'C:\inetpub\wwwroot\dataforth.com\WebShare\ProcessCheckOutTestFolder\Custom Product Rules.pdf' is denied.
|
||||
08/22/YYYY 15:51:15 | No obsolete TestFolder files were detected.
|
||||
@@ -0,0 +1,4 @@
|
||||
08/22/YYYY 15:57:38 | SyncFolder(TestFolder) started.
|
||||
08/22/YYYY 15:57:39 | Uploaded file: C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists\Custom Product Listing.pdf
|
||||
08/22/YYYY 15:57:40 | Uploaded file: C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists\Custom Product Rules.pdf
|
||||
08/22/YYYY 15:57:40 | No obsolete TestFolder files were detected.
|
||||
@@ -0,0 +1,9 @@
|
||||
08/22/YYYY 16:00:07 | SyncFolder(TestDataSheet) started.
|
||||
08/22/YYYY 16:02:13 | Exception in SyncFolder: System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
|
||||
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
|
||||
at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
|
||||
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
|
||||
at System.Xml.XmlReader.MoveToContent()
|
||||
at System.Data.DataSet.ReadXml(XmlReader reader, Boolean denyResolving)
|
||||
at CSFramework.CSFramework_Utilities.XMLData.DatasetFromXML(String xml) in C:\Users\hoffm\Documents\Visual Studio 2015\Projects\OEMData\CSFramework\CSFramework\CSFramework_Utilities\XMLData.vb:line 66
|
||||
at TestDataSheetUploader.Module1.SyncFolder(String FolderAlias) in C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\Module1.vb:line 81
|
||||
@@ -0,0 +1,8 @@
|
||||
03/31/YYYY 16:13:55 | SyncFolder(InventoryDataFolder) started.
|
||||
03/31/YYYY 16:14:00 | Exception in SyncFolder: System.Xml.XmlException: Root element is missing.
|
||||
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
|
||||
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
|
||||
at System.Xml.XmlReader.MoveToContent()
|
||||
at System.Data.DataSet.ReadXml(XmlReader reader, Boolean denyResolving)
|
||||
at TestDataSheetUploader.CSFramework_Utilities.XMLData.DatasetFromXML(String xml) in C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\XMLData.vb:line 72
|
||||
at TestDataSheetUploader.Module1.SyncFolder(String FolderAlias) in C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\Module1.vb:line 112
|
||||
@@ -0,0 +1,3 @@
|
||||
03/31/YYYY 16:18:48 | SyncFolder(InventoryDataFolder) started.
|
||||
03/31/YYYY 16:19:34 | Exception in SyncFolder: System.NullReferenceException: Object reference not set to an instance of an object.
|
||||
at TestDataSheetUploader.Module1.SyncFolder(String FolderAlias) in C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\Module1.vb:line 114
|
||||
@@ -0,0 +1,9 @@
|
||||
03/31/YYYY 16:20:24 | SyncFolder(InventoryDataFolder) started.
|
||||
03/31/YYYY 16:20:30 | Manifest downloaded with 1 files.
|
||||
03/31/YYYY 16:20:30 | Accessing local folder: C:\TestDataSheetUploader\staging
|
||||
03/31/YYYY 16:20:30 | Found at least 1 file in local folder
|
||||
03/31/YYYY 16:20:30 | Requesting upload: AvSelCat.csv
|
||||
03/31/YYYY 16:20:30 | Requesting upload: AvSelCus.csv
|
||||
03/31/YYYY 16:20:30 | Found 2 files that need to be uploaded.
|
||||
03/31/YYYY 16:20:41 | Requested InventoryDataFolder Delete: New Text Document.txt
|
||||
03/31/YYYY 16:20:41 | Found 1 files to delete.
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="UploaderServiceURL" value="https://www.dataforth.com/Services/Uploader.aspx"/>
|
||||
<add key="DirectoryManifestServiceURL" value="https://www.dataforth.com/Services/DirectoryManifest.aspx"/>
|
||||
<add key="DeleteFileServiceURL" value="https://www.dataforth.com/Services/DeleteFile.aspx"/>
|
||||
<add key="ServiceUsername" value="DataforthWebShare"/>
|
||||
<add key="ServicePassword" value="Data6277"/>
|
||||
|
||||
<add key="TestDataSheetPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
<add key="TestFolderPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
|
||||
<add key="InventoryDataStagingFolder" value="C:\TestDataSheetUploader\staging"/>
|
||||
<add key="InventoryDataSourceFolder" value="C:\TestDataSheetUploader\src"/>
|
||||
<add key="InventoryDataFiles" value="AvSelCat.csv,AvSelCus.csv"/>
|
||||
|
||||
<add key="TestMode" value="false"/>
|
||||
|
||||
</appSettings>
|
||||
<system.diagnostics>
|
||||
<sources>
|
||||
<!-- This section defines the logging configuration for My.Application.Log -->
|
||||
<source name="DefaultSource" switchName="DefaultSwitch">
|
||||
<listeners>
|
||||
<add name="FileLog"/>
|
||||
<!-- Uncomment the below section to write to the Application Event Log -->
|
||||
<!--<add name="EventLog"/>-->
|
||||
</listeners>
|
||||
</source>
|
||||
</sources>
|
||||
<switches>
|
||||
<add name="DefaultSwitch" value="Information"/>
|
||||
</switches>
|
||||
<sharedListeners>
|
||||
<add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter"/>
|
||||
<!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
|
||||
<!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
|
||||
</sharedListeners>
|
||||
</system.diagnostics>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
|
||||
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="UploaderServiceURL" value="https://www.dataforth.com/Services/Uploader.aspx"/>
|
||||
<add key="DirectoryManifestServiceURL" value="https://www.dataforth.com/Services/DirectoryManifest.aspx"/>
|
||||
<add key="DeleteFileServiceURL" value="https://www.dataforth.com/Services/DeleteFile.aspx"/>
|
||||
<add key="ServiceUsername" value="DataforthWebShare"/>
|
||||
<add key="ServicePassword" value="Data6277"/>
|
||||
|
||||
<add key="TestDataSheetPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
<add key="TestFolderPath" value="C:\Users\hoffm\Documents\Customer Folders\Dataforth\product lists"/>
|
||||
|
||||
<add key="InventoryDataStagingFolder" value="C:\TestDataSheetUploader\staging"/>
|
||||
<add key="InventoryDataSourceFolder" value="C:\TestDataSheetUploader\src"/>
|
||||
<add key="InventoryDataFiles" value="AvSelCat.csv,AvSelCus.csv"/>
|
||||
|
||||
<add key="TestMode" value="false"/>
|
||||
|
||||
</appSettings>
|
||||
<system.diagnostics>
|
||||
<sources>
|
||||
<!-- This section defines the logging configuration for My.Application.Log -->
|
||||
<source name="DefaultSource" switchName="DefaultSwitch">
|
||||
<listeners>
|
||||
<add name="FileLog"/>
|
||||
<!-- Uncomment the below section to write to the Application Event Log -->
|
||||
<!--<add name="EventLog"/>-->
|
||||
</listeners>
|
||||
</source>
|
||||
</sources>
|
||||
<switches>
|
||||
<add name="DefaultSwitch" value="Information"/>
|
||||
</switches>
|
||||
<sharedListeners>
|
||||
<add name="FileLog" type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" initializeData="FileLogWriter"/>
|
||||
<!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
|
||||
<!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
|
||||
</sharedListeners>
|
||||
</system.diagnostics>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>
|
||||
TestDataSheetUploader
|
||||
</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:TestDataSheetUploader.My.Resources.Resources">
|
||||
<summary>
|
||||
A strongly-typed resource class, for looking up localized strings, etc.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:TestDataSheetUploader.My.Resources.Resources.ResourceManager">
|
||||
<summary>
|
||||
Returns the cached ResourceManager instance used by this class.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:TestDataSheetUploader.My.Resources.Resources.Culture">
|
||||
<summary>
|
||||
Overrides the current thread's CurrentUICulture property for all
|
||||
resource lookups using this strongly typed resource class.
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<FolderContents>
|
||||
<ContentFile>
|
||||
<Filename>AvSelCat.csv</Filename>
|
||||
<Filesize>10900</Filesize>
|
||||
<DateLastUpdated>2019-06-06T05:10:18.549187Z</DateLastUpdated>
|
||||
</ContentFile>
|
||||
<ContentFile>
|
||||
<Filename>AvSelCus.csv</Filename>
|
||||
<Filesize>2529</Filesize>
|
||||
<DateLastUpdated>2019-06-06T01:10:32.1961739Z</DateLastUpdated>
|
||||
</ContentFile>
|
||||
</FolderContents>
|
||||
@@ -0,0 +1,7 @@
|
||||
' <autogenerated/>
|
||||
Option Strict Off
|
||||
Option Explicit On
|
||||
|
||||
Imports System
|
||||
Imports System.Reflection
|
||||
<Assembly: Global.System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName:=".NET Framework 4.7.2")>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
ff0a48e8544663eb773da2d9d956c2efd790e83a
|
||||
@@ -0,0 +1,22 @@
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.exe.config
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.exe
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.pdb
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.xml
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.Resources.resources
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.vbproj.GenerateResource.Cache
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.exe
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.xml
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.pdb
|
||||
C:\Users\hoffm\Documents\Visual Studio 2015\Projects\Dataforth\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.vbprojResolveAssemblyReference.cache
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.exe.config
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.exe
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.pdb
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\bin\Debug\TestDataSheetUploader.xml
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.vbproj.AssemblyReference.cache
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.vbproj.SuggestedBindingRedirects.cache
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.Resources.resources
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.vbproj.GenerateResource.cache
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.vbproj.CoreCompileInputs.cache
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.exe
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.xml
|
||||
C:\Users\kennethhoffman\source\repos\dataforth-enterprise\TestDataSheetUploader\TestDataSheetUploader\obj\Debug\TestDataSheetUploader.pdb
|
||||
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user