Initial commit to new repository
BIN
.vs/AxCommander/DesignTimeBuild/.dtbcache.v2
Normal file
BIN
.vs/AxCommander/v18/.futdcache.v2
Normal file
BIN
.vs/AxCommander/v18/.suo
Normal file
34
.vs/AxCommander/v18/DocumentLayout.backup.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"WorkspaceRootPath": "E:\\AX Commander\\",
|
||||||
|
"Documents": [
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\admin\\AppData\\Local\\Temp\\.vsdbgsrc\\47857252c2f7918acd7cde28b121406cd435acaad3354ed659f220603fb46572\\XamlReader.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"DocumentGroupContainers": [
|
||||||
|
{
|
||||||
|
"Orientation": 0,
|
||||||
|
"VerticalTabListWidth": 256,
|
||||||
|
"DocumentGroups": [
|
||||||
|
{
|
||||||
|
"DockedWidth": 200,
|
||||||
|
"SelectedChildIndex": 0,
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"Title": "XamlReader.cs",
|
||||||
|
"DocumentMoniker": "C:\\Users\\admin\\AppData\\Local\\Temp\\.vsdbgsrc\\47857252c2f7918acd7cde28b121406cd435acaad3354ed659f220603fb46572\\XamlReader.cs",
|
||||||
|
"ToolTip": "C:\\Users\\admin\\AppData\\Local\\Temp\\.vsdbgsrc\\47857252c2f7918acd7cde28b121406cd435acaad3354ed659f220603fb46572\\XamlReader.cs",
|
||||||
|
"ViewState": "AgIAAMIBAAAAAAAAAAAUwNkBAAACAAAAAQAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-03-26T21:45:20.636Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
34
.vs/AxCommander/v18/DocumentLayout.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"Version": 1,
|
||||||
|
"WorkspaceRootPath": "E:\\AX Commander\\",
|
||||||
|
"Documents": [
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|C:\\Users\\admin\\AppData\\Local\\Temp\\.vsdbgsrc\\47857252c2f7918acd7cde28b121406cd435acaad3354ed659f220603fb46572\\XamlReader.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"DocumentGroupContainers": [
|
||||||
|
{
|
||||||
|
"Orientation": 0,
|
||||||
|
"VerticalTabListWidth": 256,
|
||||||
|
"DocumentGroups": [
|
||||||
|
{
|
||||||
|
"DockedWidth": 200,
|
||||||
|
"SelectedChildIndex": 0,
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"Title": "XamlReader.cs",
|
||||||
|
"DocumentMoniker": "C:\\Users\\admin\\AppData\\Local\\Temp\\.vsdbgsrc\\47857252c2f7918acd7cde28b121406cd435acaad3354ed659f220603fb46572\\XamlReader.cs",
|
||||||
|
"ToolTip": "C:\\Users\\admin\\AppData\\Local\\Temp\\.vsdbgsrc\\47857252c2f7918acd7cde28b121406cd435acaad3354ed659f220603fb46572\\XamlReader.cs",
|
||||||
|
"ViewState": "AgIAAMIBAAAAAAAAAAAYwNkBAAACAAAAAQAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-03-26T21:45:20.636Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
.vs/ProjectEvaluation/axcommander.metadata.v10.bin
Normal file
BIN
.vs/ProjectEvaluation/axcommander.projects.v10.bin
Normal file
BIN
.vs/ProjectEvaluation/axcommander.strings.v10.bin
Normal file
540
AXCommander_SRS_draft.rtf
Normal file
@@ -0,0 +1,540 @@
|
|||||||
|
{\rtf1\ansi\ansicpg949\cocoartf2868
|
||||||
|
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset129 AppleSDGothicNeo-Regular;\f2\fnil\fcharset0 LucidaGrande;
|
||||||
|
}
|
||||||
|
{\colortbl;\red255\green255\blue255;}
|
||||||
|
{\*\expandedcolortbl;;}
|
||||||
|
\paperw11900\paperh16840\margl1440\margr1440\vieww20200\viewh15100\viewkind0
|
||||||
|
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural\partightenfactor0
|
||||||
|
|
||||||
|
\f0\fs24 \cf0 1.
|
||||||
|
\f1 \'bd\'c3\'bd\'ba\'c5\'db
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'d9\'bd\'c9
|
||||||
|
\f0
|
||||||
|
\f1 \'be\'c6\'c5\'b0\'c5\'d8\'c3\'b3
|
||||||
|
\f0 \
|
||||||
|
|
||||||
|
\f1 \'c1\'d6\'bf\'e4
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'f0\'b5\'e2
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'b8\'bc\'ba\
|
||||||
|
* \'c0\'a9\'b5\'b5\'bf\'ec os\'bf\'a1\'bc\'ad \'b5\'bf\'c0\'db\'c7\'cf\'b4\'c2 \'c7\'c1\'b7\'ce\'b1\'d7\'b7\'a5\'c0\'b8\'b7\'ce \'c1\'a4\'c0\'c7
|
||||||
|
\f0 \
|
||||||
|
* Input Listener (Global Hook):
|
||||||
|
\f1 \'be\'ee\'b6\'b2
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'c1\'b7\'ce\'b1\'d7\'b7\'a5
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'a7\'bf\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d6\'b5\'e7
|
||||||
|
\f0 Alt + Space
|
||||||
|
\f1 \'bf\'cd
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'b0\'c0\'ba
|
||||||
|
\f0
|
||||||
|
\f1 \'b4\'dc\'c3\'e0\'c5\'b0\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'a8\'c1\'f6\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* Context Manager:
|
||||||
|
\f1 \'c7\'f6\'c0\'e7
|
||||||
|
\f0
|
||||||
|
\f1 \'bf\'ad\'b7\'c1
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d6\'b4\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'a9\'b5\'b5\'bf\'ec\'b5\'e9\'c0\'c7
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'da\'b5\'e9
|
||||||
|
\f0 (HWND),
|
||||||
|
\f1 \'c7\'c1\'b7\'ce\'bc\'bc\'bd\'ba
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'e6\'b7\'ce
|
||||||
|
\f0 ,
|
||||||
|
\f1 \'c3\'a2
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'a7\'c4\'a1
|
||||||
|
\f0 (Rect)
|
||||||
|
\f1 \'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'ba\'b3\'c0\'bc\'a6\'c0\'b8\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'c4\'b8\'c3\'b3\'c7\'cf\'b0\'ed
|
||||||
|
\f0
|
||||||
|
\f1 \'ba\'b9\'bf\'f8\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* Command Resolver:
|
||||||
|
\f1 \'c0\'d4\'b7\'c2\'b5\'c8
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'ed\'b7\'c9\'be\'ee
|
||||||
|
\f0 (
|
||||||
|
\f1 \'bf\'b9
|
||||||
|
\f0 : @nas, !dev)
|
||||||
|
\f1 \'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'d8\'bc\'ae\'c7\'cf\'bf\'a9
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'cc\'b8\'ae
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'a4\'c0\'c7\'b5\'c8
|
||||||
|
\f0
|
||||||
|
\f1 \'be\'d7\'bc\'c7
|
||||||
|
\f0 (
|
||||||
|
\f1 \'c6\'fa\'b4\'f5
|
||||||
|
\f0
|
||||||
|
\f1 \'bf\'ad\'b1\'e2
|
||||||
|
\f0 ,
|
||||||
|
\f1 \'b9\'e8\'c4\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c7\'c7\'e0
|
||||||
|
\f0 ,
|
||||||
|
\f1 \'c0\'a9\'b5\'b5\'bf\'ec
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'a4\'b7\'c4
|
||||||
|
\f0 )
|
||||||
|
\f1 \'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'c5\'c7\'ce\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* Fuzzy Engine:
|
||||||
|
\f1 \'c6\'c4\'c0\'cf\'b8\'ed\'c0\'cc\'b3\'aa
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'b0\'bf\'f6\'b5\'e5\'c0\'c7
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'cf\'ba\'ce\'b8\'b8
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d4\'b7\'c2\'c7\'d8\'b5\'b5
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'a1\'c0\'e5
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'af\'bb\'e7\'c7\'d1
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'d7\'b8\'f1\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'ca\'b0\'ed\'bc\'d3\'c0\'b8\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'a3\'be\'c6\'c1\'dd\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* max os\uc0\u51032 \u50508 \u54532 \u47112 \u46300 \u50752 \u50976 \u49324 \u54620 \u44592 \u45733 \u51012 \u50952 \u46020 \u50864 os\u50640 \u44396 \u52629 \
|
||||||
|
2.
|
||||||
|
\f1 \'c1\'d6\'bf\'e4
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'e2\'b4\'c9
|
||||||
|
\f0
|
||||||
|
\f1 \'bb\'f3\'bc\'bc
|
||||||
|
\f0 (Feature List)\
|
||||||
|
A.
|
||||||
|
\f1 \'bf\'f6\'c5\'a9\'bd\'ba\'c6\'e4\'c0\'cc\'bd\'ba
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'ba\'b3\'c0\'bc\'a6
|
||||||
|
\f0 &
|
||||||
|
\f1 \'bd\'c3\'c7\'c1\'c6\'ae
|
||||||
|
\f0 (The Shifter)\
|
||||||
|
|
||||||
|
\f1 \'b4\'dc\'bc\'f8\'c8\'f7
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'c1\'b7\'ce\'b1\'d7\'b7\'a5\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'b6\'e7\'bf\'ec\'b4\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'cd\'c0\'cc
|
||||||
|
\f0
|
||||||
|
\f1 \'be\'c6\'b4\'cf\'b6\'f3
|
||||||
|
\f0 , '
|
||||||
|
\f1 \'be\'ee\'b6\'b2
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'a7\'c4\'a1\'bf\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'be\'ee\'b6\'b2
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'a9\'b1\'e2\'b7\'ce
|
||||||
|
\f0 '
|
||||||
|
\f1 \'b6\'b0
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d6\'b4\'c2\'c1\'f6\'b1\'ee\'c1\'f6
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'fc\'b8\'ae\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* Snapshot Capture:
|
||||||
|
\f1 \'c7\'f6\'c0\'e7
|
||||||
|
\f0
|
||||||
|
\f1 \'c8\'ad\'b8\'e9\'bf\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'b6\'b0
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d6\'b4\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'f0\'b5\'e7
|
||||||
|
\f0
|
||||||
|
\f1 \'be\'f7\'b9\'ab\'bf\'eb
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'a2
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'e8\'c4\'a1\'b8\'a6
|
||||||
|
\f0 '
|
||||||
|
\f1 \'c7\'c1\'b7\'ce\'c7\'ca
|
||||||
|
\f0 '
|
||||||
|
\f1 \'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'fa\'c0\'e5\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 . (
|
||||||
|
\f1 \'bf\'b9
|
||||||
|
\f0 :
|
||||||
|
\f1 \'bf\'de\'c2\'ca\'bf\'a3
|
||||||
|
\f0 VS Code,
|
||||||
|
\f1 \'bf\'c0\'b8\'a5\'c2\'ca
|
||||||
|
\f0
|
||||||
|
\f1 \'bb\'f3\'b4\'dc\'bf\'a3
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'e2\'c8\'b9\'bc\'ad
|
||||||
|
\f0 PDF,
|
||||||
|
\f1 \'c7\'cf\'b4\'dc\'bf\'a3
|
||||||
|
\f0 SQL
|
||||||
|
\f1 \'c5\'f8
|
||||||
|
\f0 )\
|
||||||
|
* Instant Restore: !dev
|
||||||
|
\f1 \'b8\'ed\'b7\'c9
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c3
|
||||||
|
\f0 ,
|
||||||
|
\f1 \'c0\'fa\'c0\'e5\'b5\'c8
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'c1\'b7\'ce\'c7\'ca\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'ba\'d2\'b7\'af\'bf\'cd
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'a2\'b5\'e9\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'ad\'c1\'a6\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'e7\'b9\'e8\'c4\'a1\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* Multi-Monitor Support:
|
||||||
|
\f1 \'b5\'e0\'be\'f3
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'f0\'b4\'cf\'c5\'cd
|
||||||
|
\f0
|
||||||
|
\f1 \'c8\'af\'b0\'e6\'bf\'a1\'bc\'ad\'b5\'b5
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'a2
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'f0\'b4\'cf\'c5\'cd\'ba\'b0
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'a2
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'e8\'c4\'a1\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'a4\'c8\'ae\'c8\'f7
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'e2\'be\'ef\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
B.
|
||||||
|
\f1 \'bd\'c3\'b8\'c7\'c6\'bd
|
||||||
|
\f0
|
||||||
|
\f1 \'c4\'bf\'b8\'c7\'b5\'e5
|
||||||
|
\f0
|
||||||
|
\f1 \'b7\'b1\'c3\'b3
|
||||||
|
\f0 (The Alfred)\
|
||||||
|
|
||||||
|
\f1 \'c5\'b0\'ba\'b8\'b5\'e5\'b8\'b8\'c0\'b8\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'b6\'bf\'ec\'bd\'ba
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'ac\'b8\'af
|
||||||
|
\f0
|
||||||
|
\f1 \'bc\'f6\'bd\'ca
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'f8\'c0\'c7
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'a1\'c4\'a1\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'b8\'b5\'e9\'be\'ee\'b3\'c0\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* Smart Aliases:
|
||||||
|
\f1 \'b1\'e4
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'e6\'b7\'ce\'b3\'aa
|
||||||
|
\f0
|
||||||
|
\f1 \'ba\'b9\'c0\'e2\'c7\'d1
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'ed\'b7\'c9\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'c2\'aa\'c0\'ba
|
||||||
|
\f0
|
||||||
|
\f1 \'ba\'b0\'c4\'aa\'c0\'b8\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'b5\'ee\'b7\'cf\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
* @blog
|
||||||
|
\f2 \uc0\u8594
|
||||||
|
\f0 swarchitect.net
|
||||||
|
\f1 \'b0\'fc\'b8\'ae\'c0\'da
|
||||||
|
\f0
|
||||||
|
\f1 \'c6\'e4\'c0\'cc\'c1\'f6
|
||||||
|
\f0
|
||||||
|
\f1 \'bf\'c0\'c7\'c2
|
||||||
|
\f0 \
|
||||||
|
* #jira
|
||||||
|
\f2 \uc0\u8594
|
||||||
|
\f0
|
||||||
|
\f1 \'b3\'bb\'b0\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'b4\'e3\'b4\'e7\'c7\'d1
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'d6\'bd\'c5
|
||||||
|
\f0
|
||||||
|
\f1 \'c6\'bc\'c4\'cf
|
||||||
|
\f0
|
||||||
|
\f1 \'c6\'e4\'c0\'cc\'c1\'f6\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'d9\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'cc\'b5\'bf
|
||||||
|
\f0 \
|
||||||
|
* Clipboard Transformer:
|
||||||
|
\f1 \'ba\'b9\'bb\'e7\'c7\'d1
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'d8\'bd\'ba\'c6\'ae\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'d4\'c4\'a2\'bf\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'b5\'fb\'b6\'f3
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'a1\'b0\'f8\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 . (
|
||||||
|
\f1 \'bf\'b9
|
||||||
|
\f0 : JSON
|
||||||
|
\f1 \'c6\'f7\'b8\'cb\'c6\'c3
|
||||||
|
\f0 ,
|
||||||
|
\f1 \'c0\'af\'b4\'d0\'bd\'ba
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'b8\'c0\'d3\'bd\'ba\'c5\'c6\'c7\'c1
|
||||||
|
\f0
|
||||||
|
\f1 \'ba\'af\'c8\'af
|
||||||
|
\f0
|
||||||
|
\f1 \'b5\'ee
|
||||||
|
\f0 )\
|
||||||
|
3. UI/UX
|
||||||
|
\f1 \'b5\'f0\'c0\'da\'c0\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'a1\'c0\'cc\'b5\'e5
|
||||||
|
\f0 (WPF
|
||||||
|
\f1 \'b1\'e2\'b9\'dd
|
||||||
|
\f0 )\
|
||||||
|
|
||||||
|
\f1 \'bb\'e7\'bf\'eb\'c0\'da\'c0\'c7
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c3\'b0\'a2\'c0\'fb
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'e6\'c7\'d8\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'d6\'bc\'d2\'c8\'ad\'c7\'cf\'b8\'e9\'bc\'ad
|
||||||
|
\f0
|
||||||
|
\f1 \'bc\'bc\'b7\'c3\'b5\'c8
|
||||||
|
\f0
|
||||||
|
\f1 \'b4\'c0\'b3\'a6\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'d6\'b4\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'b5\'f0\'c0\'da\'c0\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'e6\'c7\'e2\'c0\'d4\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
|
|
||||||
|
\f1 \'bf\'e4\'bc\'d2
|
||||||
|
\f0 |
|
||||||
|
\f1 \'b5\'f0\'c0\'da\'c0\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'c7\'c0\'e5
|
||||||
|
\f0
|
||||||
|
\f1 \'bb\'e7\'c7\'d7
|
||||||
|
\f0 |\
|
||||||
|
|---|---|\
|
||||||
|
|
|
||||||
|
\f1 \'c3\'a2
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'fc\'c5\'c2
|
||||||
|
\f0 |
|
||||||
|
\f1 \'c8\'ad\'b8\'e9
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'df\'be\'d3\'bf\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'b6\'df\'b4\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'f5\'b8\'ed\'b5\'b5
|
||||||
|
\f0 (Opacity)
|
||||||
|
\f1 \'b0\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'fb\'bf\'eb\'b5\'c8
|
||||||
|
\f0
|
||||||
|
\f1 \'b9\'d9
|
||||||
|
\f0 (Bar)
|
||||||
|
\f1 \'c7\'fc\'c5\'c2
|
||||||
|
\f0 |\
|
||||||
|
|
|
||||||
|
\f1 \'c5\'d7\'b8\'b6
|
||||||
|
\f0 |
|
||||||
|
\f1 \'bd\'c3\'bd\'ba\'c5\'db
|
||||||
|
\f0
|
||||||
|
\f1 \'bc\'b3\'c1\'a4\'bf\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'b5\'fb\'b8\'a5
|
||||||
|
\f0
|
||||||
|
\f1 \'b4\'d9\'c5\'a9
|
||||||
|
\f0 /
|
||||||
|
\f1 \'b6\'f3\'c0\'cc\'c6\'ae
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'f0\'b5\'e5
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'da\'b5\'bf
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'fc\'c8\'af
|
||||||
|
\f0 |\
|
||||||
|
|
|
||||||
|
\f1 \'b0\'e1\'b0\'fa
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'ae\'bd\'ba\'c6\'ae
|
||||||
|
\f0 |
|
||||||
|
\f1 \'b8\'ed\'b7\'c9\'be\'ee
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d4\'b7\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c3
|
||||||
|
\f0
|
||||||
|
\f1 \'be\'c6\'b7\'a1\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'d6\'b4\'eb
|
||||||
|
\f0 5~7
|
||||||
|
\f1 \'b0\'b3\'c0\'c7
|
||||||
|
\f0
|
||||||
|
\f1 \'c3\'df\'c3\'b5
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'ae\'bd\'ba\'c6\'ae\'b0\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'b8\'ae\'bd\'ba\'c6\'ae\'ba\'e4
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'fc\'c5\'c2\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'a5\'bd\'c3
|
||||||
|
\f0 |\
|
||||||
|
|
|
||||||
|
\f1 \'be\'d6\'b4\'cf\'b8\'de\'c0\'cc\'bc\'c7
|
||||||
|
\f0 |
|
||||||
|
\f1 \'c8\'a3\'c3\'e2
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c3
|
||||||
|
\f0
|
||||||
|
\f1 \'c6\'e4\'c0\'cc\'b5\'e5\'c0\'ce
|
||||||
|
\f0 (Fade-in),
|
||||||
|
\f1 \'bd\'c7\'c7\'e0
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c3
|
||||||
|
\f0
|
||||||
|
\f1 \'bb\'e7\'b6\'f3\'c1\'f6\'b4\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'c8\'bf\'b0\'fa\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'bc\'d3\'b5\'b5\'b0\'a8
|
||||||
|
\f0
|
||||||
|
\f1 \'ba\'ce\'bf\'a9
|
||||||
|
\f0 |\
|
||||||
|
4.
|
||||||
|
\f1 \'b1\'b8\'c7\'f6\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'a7\'c7\'d1
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'d9\'bd\'c9
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'e2\'bc\'fa
|
||||||
|
\f0
|
||||||
|
\f1 \'c6\'f7\'c0\'ce\'c6\'ae
|
||||||
|
\f0 (C# .NET)\
|
||||||
|
|
||||||
|
\f1 \'c0\'cc
|
||||||
|
\f0
|
||||||
|
\f1 \'b5\'b5\'b1\'b8\'c0\'c7
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c9\'c0\'e5\'c0\'ba
|
||||||
|
\f0 Windows API
|
||||||
|
\f1 \'c1\'a6\'be\'ee\'bf\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d6\'bd\'c0\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
*
|
||||||
|
\f1 \'c0\'a9\'b5\'b5\'bf\'ec
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'a6\'be\'ee
|
||||||
|
\f0 : User32.dll
|
||||||
|
\f1 \'c0\'c7
|
||||||
|
\f0 GetWindowPlacement, SetWindowPos, ShowWindow
|
||||||
|
\f1 \'c7\'d4\'bc\'f6\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'eb\'c7\'d8
|
||||||
|
\f0
|
||||||
|
\f1 \'b4\'d9\'b8\'a5
|
||||||
|
\f0
|
||||||
|
\f1 \'be\'db\'c0\'c7
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'a7\'c4\'a1\'bf\'cd
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'a9\'b1\'e2\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'b0\'ad\'c1\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'b6\'c1\'a4\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
*
|
||||||
|
\f1 \'b1\'db\'b7\'ce\'b9\'fa
|
||||||
|
\f0
|
||||||
|
\f1 \'b4\'dc\'c3\'e0\'c5\'b0
|
||||||
|
\f0 : RegisterHotKey
|
||||||
|
\f1 \'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'bb\'e7\'bf\'eb\'c7\'cf\'bf\'a9
|
||||||
|
\f0
|
||||||
|
\f1 \'bd\'c3\'bd\'ba\'c5\'db
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'fc\'c3\'bc\'bf\'a1\'bc\'ad
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'db\'b5\'bf\'c7\'cf\'b4\'c2
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'d6\'c5\'b0\'b8\'a6
|
||||||
|
\f0
|
||||||
|
\f1 \'b1\'b8\'c7\'f6\'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
*
|
||||||
|
\f1 \'b5\'a5\'c0\'cc\'c5\'cd
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'fa\'c0\'e5
|
||||||
|
\f0 :
|
||||||
|
\f1 \'ba\'b9\'c0\'e2\'c7\'d1
|
||||||
|
\f0 DB
|
||||||
|
\f1 \'b4\'eb\'bd\'c5
|
||||||
|
\f0 JSON
|
||||||
|
\f1 \'c6\'c4\'c0\'cf
|
||||||
|
\f0 (settings.json)
|
||||||
|
\f1 \'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'bb\'e7\'bf\'eb\'c7\'cf\'bf\'a9
|
||||||
|
\f0
|
||||||
|
\f1 \'bb\'e7\'bf\'eb\'c0\'da\'b0\'a1
|
||||||
|
\f0
|
||||||
|
\f1 \'c1\'f7\'c1\'a2
|
||||||
|
\f0
|
||||||
|
\f1 \'c5\'d8\'bd\'ba\'c6\'ae
|
||||||
|
\f0
|
||||||
|
\f1 \'bf\'a1\'b5\'f0\'c5\'cd\'b7\'ce
|
||||||
|
\f0
|
||||||
|
\f1 \'ba\'b0\'c4\'aa\'c0\'bb
|
||||||
|
\f0
|
||||||
|
\f1 \'bc\'f6\'c1\'a4\'c7\'d2
|
||||||
|
\f0
|
||||||
|
\f1 \'bc\'f6
|
||||||
|
\f0
|
||||||
|
\f1 \'c0\'d6\'b0\'d4
|
||||||
|
\f0
|
||||||
|
\f1 \'c7\'d5\'b4\'cf\'b4\'d9
|
||||||
|
\f0 .\
|
||||||
|
}
|
||||||
575
AXCommander_SRS_v1.0.html
Normal file
@@ -0,0 +1,575 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko"><head><meta charset="utf-8">
|
||||||
|
<title>AXCommander_SRS_v1.0</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: "맑은 고딕", "Malgun Gothic", sans-serif; font-size: 11pt; color: #1a1a1a; line-height: 1.7; max-width: 900px; margin: 0 auto; padding: 40px 20px; }
|
||||||
|
h1 { font-size: 22pt; color: #1F3864; border-bottom: 3px solid #4472C4; padding-bottom: 8px; margin-top: 32px; }
|
||||||
|
h2 { font-size: 16pt; color: #2E75B6; border-bottom: 2px solid #B8CCE4; padding-bottom: 4px; margin-top: 28px; }
|
||||||
|
h3 { font-size: 13pt; color: #44546A; margin-top: 22px; }
|
||||||
|
h4 { font-size: 12pt; color: #44546A; margin-top: 18px; }
|
||||||
|
p { margin: 6px 0; }
|
||||||
|
table { border-collapse: collapse; width: 100%; margin: 12px 0; }
|
||||||
|
th { background: #2E75B6; color: white; padding: 8px 10px; text-align: left; font-size: 10pt; }
|
||||||
|
td { padding: 6px 10px; border: 1px solid #D6E4F0; font-size: 10pt; }
|
||||||
|
tr:nth-child(even) td { background: #EBF3FB; }
|
||||||
|
ul, ol { margin: 6px 0 6px 24px; }
|
||||||
|
li { margin: 3px 0; }
|
||||||
|
code { font-family: Consolas, "D2Coding", monospace; background: #F0F0F0; padding: 1px 4px; border-radius: 3px; font-size: 10pt; }
|
||||||
|
.footer { text-align: right; color: #999; font-size: 9pt; margin-top: 40px; border-top: 1px solid #ddd; padding-top: 8px; }
|
||||||
|
</style></head><body>
|
||||||
|
|
||||||
|
<p><b>OLEDi Commander</b></p>
|
||||||
|
<p>Software Requirements Specification</p>
|
||||||
|
<p>Windows 전용 시맨틱 런처 & 워크스페이스 매니저</p>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>항목</b></th><th><b>내용</b></th></tr>
|
||||||
|
<tr><td>문서 버전</td><td>v1.0</td></tr>
|
||||||
|
<tr><td>작성일</td><td>2026-03-21</td></tr>
|
||||||
|
<tr><td>최종 검토일</td><td>2026-03-21</td></tr>
|
||||||
|
<tr><td>상태</td><td>초안 (Draft)</td></tr>
|
||||||
|
<tr><td>대상 플랫폼</td><td>Windows 10 / 11 (x64)</td></tr>
|
||||||
|
<tr><td>구현 언어</td><td>C# / .NET 8 / WPF</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>목차</b></h1>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>1. 개요 (Overview)</b></h1>
|
||||||
|
<h2><b>1.1 프로젝트 목적</b></h2>
|
||||||
|
<p>OLEDi Commander는 macOS 생산성 도구 Alfred에서 영감을 받아, Windows 환경에서 동등하거나 그 이상의 생산성을 제공하기 위해 설계된 키보드 우선(Keyboard-first) 런처 겸 워크스페이스 매니저입니다.</p>
|
||||||
|
<p>전통적인 마우스 중심 UI 조작을 Alt+Space 단축키 하나로 대체하여, 개발자·파워유저가 컨텍스트 전환 비용 없이 빠르게 작업을 수행할 수 있도록 합니다.</p>
|
||||||
|
|
||||||
|
<h2><b>1.2 범위 (Scope)</b></h2>
|
||||||
|
<p>본 문서는 OLEDi Commander 1.0 릴리스를 대상으로 하며, 아래 두 핵심 모듈을 포함합니다.</p>
|
||||||
|
<ul>
|
||||||
|
<li>The Shifter: 워크스페이스 창 배치 스냅샷 및 복원</li>
|
||||||
|
<li>The Alfred: 시맨틱 커맨드 런처 (별칭, 클립보드 변환, Fuzzy 검색)</li>
|
||||||
|
</ul>
|
||||||
|
<p>아래 항목은 v1.0 범위에서 제외됩니다.</p>
|
||||||
|
<ul>
|
||||||
|
<li>macOS / Linux 지원</li>
|
||||||
|
<li>클라우드 동기화</li>
|
||||||
|
<li>플러그인 마켓플레이스 UI (v2.0 예정)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><b>1.3 용어 정의 (Glossary)</b></h2>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>용어</b></th><th><b>정의</b></th></tr>
|
||||||
|
<tr><td>HWND</td><td>Windows API에서 창(Window)을 식별하는 핸들 값</td></tr>
|
||||||
|
<tr><td>Rect</td><td>창의 좌상단·우하단 좌표로 이루어진 사각형 구조체</td></tr>
|
||||||
|
<tr><td>Profile</td><td>특정 시점의 창 배치 및 크기 정보를 저장한 JSON 객체</td></tr>
|
||||||
|
<tr><td>Alias</td><td>긴 경로·명령을 짧게 치환하는 사용자 정의 키워드</td></tr>
|
||||||
|
<tr><td>Fuzzy Search</td><td>오타·부분 입력도 유사 항목을 찾아주는 비정확 검색</td></tr>
|
||||||
|
<tr><td>Global Hook</td><td>어떤 앱이 포커스를 갖고 있어도 키 입력을 감지하는 OS 훅</td></tr>
|
||||||
|
<tr><td>Plugin</td><td>CommandResolver에 새로운 ActionHandler를 추가하는 확장 단위</td></tr>
|
||||||
|
<tr><td>Skill</td><td>Plugin의 다른 표현. 사용자 정의 실행 규칙 묶음</td></tr>
|
||||||
|
<tr><td>settings.json</td><td>사용자 설정 및 Alias를 저장하는 로컬 JSON 파일</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>1.4 참조 문서</b></h2>
|
||||||
|
<ul>
|
||||||
|
<li>Microsoft Docs – User32.dll API Reference</li>
|
||||||
|
<li>WPF Documentation (.NET 8)</li>
|
||||||
|
<li>Windows Accessibility API (MSAA / UI Automation)</li>
|
||||||
|
<li>Alfred App – https://www.alfredapp.com (인터페이스 참조)</li>
|
||||||
|
</ul>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>2. 시스템 아키텍처</b></h1>
|
||||||
|
<p>OLEDi Commander는 단일 프로세스(Single-process) 구조이며, 아래 5개 핵심 모듈로 구성됩니다. 모든 모듈은 의존성 주입(DI) 방식으로 연결되어 테스트 및 확장이 용이합니다.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>모듈</b></th><th><b>역할</b></th><th><b>핵심 기술</b></th></tr>
|
||||||
|
<tr><td>Input Listener</td><td>글로벌 키 훅 – 어떤 앱에서도 Alt+Space 감지</td><td>WH_KEYBOARD_LL, RegisterHotKey</td></tr>
|
||||||
|
<tr><td>Context Manager</td><td>열린 창의 HWND, Rect, 프로세스 경로 수집 및 복원</td><td>EnumWindows, GetWindowPlacement, SetWindowPos</td></tr>
|
||||||
|
<tr><td>Command Resolver</td><td>입력 텍스트 파싱 → ActionHandler 라우팅</td><td>Prefix 테이블, ActionHandler 인터페이스</td></tr>
|
||||||
|
<tr><td>Fuzzy Engine</td><td>파일명·키워드 부분 입력으로 빠른 유사 항목 탐색</td><td>Fuse.js 알고리즘 포팅 또는 FuzzySharp</td></tr>
|
||||||
|
<tr><td>Plugin Host</td><td>외부 .dll 또는 JSON 기반 스킬을 로드·실행</td><td>Reflection, IActionHandler 인터페이스</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>2.1 모듈 간 데이터 흐름</b></h2>
|
||||||
|
<p>[사용자 키 입력] → Input Listener → Command Resolver → ActionHandler (Shifter / Alfred / Plugin)</p>
|
||||||
|
<p>[창 배치 저장] → Context Manager → Profile JSON → settings.json</p>
|
||||||
|
<p>[창 배치 복원] → settings.json → Context Manager → User32 API</p>
|
||||||
|
|
||||||
|
<h2><b>2.2 Prefix 라우팅 테이블</b></h2>
|
||||||
|
<p>Command Resolver는 입력 텍스트의 첫 번째 토큰(prefix)을 기준으로 ActionHandler를 선택합니다. 빌트인 prefix는 다음과 같습니다.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>Prefix</b></th><th><b>타입</b></th><th><b>예시</b></th><th><b>동작</b></th></tr>
|
||||||
|
<tr><td>!</td><td>워크스페이스</td><td>!dev</td><td>저장된 "dev" 프로필 즉시 복원</td></tr>
|
||||||
|
<tr><td>@</td><td>URL / 웹</td><td>@blog</td><td>settings.json의 해당 URL 브라우저로 오픈</td></tr>
|
||||||
|
<tr><td>#</td><td>동적 API</td><td>#jira</td><td>설정된 API 어댑터 호출 후 결과 표시</td></tr>
|
||||||
|
<tr><td>></td><td>터미널 명령</td><td>>git status</td><td>Windows Terminal / PowerShell에서 실행</td></tr>
|
||||||
|
<tr><td>~</td><td>파일 경로</td><td>~projects</td><td>등록된 폴더 경로를 탐색기로 오픈</td></tr>
|
||||||
|
<tr><td>(없음)</td><td>Fuzzy 검색</td><td>vsc</td><td>인덱스에서 유사 파일·앱·Alias 검색</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>확장 가능성</b><br/>위 prefix 목록은 settings.json의 "prefixMap" 배열을 통해 사용자가 직접 추가·변경할 수 있습니다.<br/>플러그인 개발자는 IActionHandler 인터페이스를 구현하는 .dll을 제공하여 새로운 prefix 동작을 등록합니다.<br/>자세한 내용은 섹션 7 개발자 확장 가이드를 참조하십시오.</th></tr>
|
||||||
|
</table>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>3. 기능 요구사항</b></h1>
|
||||||
|
<h2><b>3.1 워크스페이스 스냅샷 & 시프트 (The Shifter)</b></h2>
|
||||||
|
<p>"어떤 위치에 어떤 크기로" 떠 있는지까지 관리하는 워크스페이스 레이아웃 엔진입니다. 단순 앱 실행을 넘어 창의 상태(State)를 완전히 복원합니다.</p>
|
||||||
|
|
||||||
|
<h3><b>3.1.1 Snapshot Capture</b></h3>
|
||||||
|
<ul>
|
||||||
|
<li>현재 화면에 있는 모든 가시(Visible) 업무용 창의 배치를 "프로필"로 저장</li>
|
||||||
|
<li>저장 정보: HWND, 프로세스 실행 경로(EXE), 창 제목, Rect (좌상단 x/y, 폭, 높이), 최소화/최대화/일반 상태(ShowCmd)</li>
|
||||||
|
<li>저장 위치: settings.json의 "profiles" 배열</li>
|
||||||
|
<li>저장 명령어: !save <프로필명> 또는 UI의 저장 버튼</li>
|
||||||
|
<li>시스템 트레이 UI(Task Bar) 및 바탕화면은 캡처 제외</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3><b>3.1.2 Instant Restore</b></h3>
|
||||||
|
<ul>
|
||||||
|
<li>!<프로필명> 입력 시 해당 프로필의 창 배치를 강제 복원</li>
|
||||||
|
<li>복원 순서: 1) 저장된 EXE 경로로 프로세스 존재 확인 → 2) HWND 유효성 검사 → 3) SetWindowPos 호출</li>
|
||||||
|
<li>앱이 실행 중이지 않은 경우: 자동으로 EXE를 실행한 후 창 생성을 최대 3초간 대기</li>
|
||||||
|
<li>3초 내 창이 생성되지 않으면 해당 앱을 건너뛰고 나머지 복원 진행, 결과 알림 표시</li>
|
||||||
|
<li>관리자 권한 창(elevated process)은 복원 시 UAC 프롬프트 없이 위치만 조정 (권한 상승 없이 처리 가능한 범위 내에서 수행)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3><b>3.1.3 Profile 관리</b></h3>
|
||||||
|
<ul>
|
||||||
|
<li>목록 보기: 런처 UI에서 !<엔터> 입력 시 저장된 프로필 전체 목록 표시</li>
|
||||||
|
<li>이름 변경: !rename <현재명> <새이름></li>
|
||||||
|
<li>삭제: !delete <프로필명> (확인 다이얼로그 필요)</li>
|
||||||
|
<li>내보내기/가져오기: settings.json 파일 직접 공유 가능 (JSON 스키마 준수 시)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3><b>3.1.4 Multi-Monitor 지원</b></h3>
|
||||||
|
<ul>
|
||||||
|
<li>각 모니터의 DPI 및 좌표계 독립 저장</li>
|
||||||
|
<li>모니터 구성 변경 감지: WM_DISPLAYCHANGE 메시지 수신 시 활성 프로필과 현재 모니터 구성 비교</li>
|
||||||
|
<li>모니터 불일치 시 동작 옵션 (settings.json으로 설정 가능):</li>
|
||||||
|
<li>"fit": 사용 가능한 모니터에 좌표 스케일링하여 배치</li>
|
||||||
|
<li>"skip": 해당 모니터의 창만 건너뜀</li>
|
||||||
|
<li>"warn": 복원 전 경고 팝업 표시 (기본값)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><b>3.2 시맨틱 커맨드 런처 (The Alfred)</b></h2>
|
||||||
|
<p>키보드만으로 마우스 클릭 수십 번의 가치를 만들어냅니다. Alt+Space → 명령어 입력의 단일 패턴으로 모든 작업을 처리합니다.</p>
|
||||||
|
|
||||||
|
<h3><b>3.2.1 Smart Aliases</b></h3>
|
||||||
|
<p>긴 경로나 복잡한 명령을 짧은 별칭으로 등록합니다. settings.json의 "aliases" 배열로 관리됩니다.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>Alias 타입</b></th><th><b>예시</b></th><th><b>동작 설명</b></th></tr>
|
||||||
|
<tr><td>url</td><td>@blog → https://swarchitect.net/admin</td><td>브라우저로 URL 오픈</td></tr>
|
||||||
|
<tr><td>folder</td><td>~proj → C:\\Dev\\Projects</td><td>탐색기로 폴더 오픈</td></tr>
|
||||||
|
<tr><td>app</td><td>@term → C:\\Windows\\wt.exe</td><td>지정 실행파일 실행</td></tr>
|
||||||
|
<tr><td>batch</td><td>>build → cmd /c build.bat</td><td>커맨드 실행 (출력 창 선택)</td></tr>
|
||||||
|
<tr><td>api</td><td>#jira → JiraAdapter (토큰 설정 필요)</td><td>동적 데이터 조회 후 결과 표시</td></tr>
|
||||||
|
<tr><td>clipboard</td><td>$upper → UPPER_CASE 변환</td><td>현재 클립보드 텍스트 변환</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3><b>3.2.2 Fuzzy Engine</b></h3>
|
||||||
|
<ul>
|
||||||
|
<li>검색 범위: 사용자 정의 인덱스 폴더(기본: 바탕화면, 시작 메뉴, 최근 파일) + 등록된 모든 Alias</li>
|
||||||
|
<li>인덱싱: 앱 시작 시 1회 전체 인덱싱, 이후 FileSystemWatcher로 변경 감지 시 증분 업데이트</li>
|
||||||
|
<li>응답 목표: 타이핑 후 100ms 이내에 결과 표시 (로컬 인덱스 기준)</li>
|
||||||
|
<li>결과 랭킹 기준: 1) 정확히 일치하는 Alias 최우선, 2) 문자열 유사도, 3) 최근 실행 빈도 가중치</li>
|
||||||
|
<li>최대 결과 수: UI에 5~7개 표시 (설정으로 최대 20개까지 확장 가능)</li>
|
||||||
|
<li>대소문자 구분 없음, 한글 초성 검색 지원 (예: "ㅂㅅ" → "Visual Studio")</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3><b>3.2.3 Clipboard Transformer</b></h3>
|
||||||
|
<p>복사한 텍스트를 규칙에 따라 가공합니다. $ prefix로 호출하며, 변환 결과를 클립보드에 덮어쓴 후 활성 창에 붙여넣기(Ctrl+V) 시뮬레이션을 수행합니다.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>빌트인 변환</b></th><th><b>명령</b></th><th><b>예시</b></th></tr>
|
||||||
|
<tr><td>JSON 포맷팅</td><td>$json</td><td>{"a":1} → 들여쓰기 적용 JSON</td></tr>
|
||||||
|
<tr><td>유닉스 타임스탬프 → 날짜</td><td>$ts</td><td>1700000000 → 2023-11-14 22:13:20</td></tr>
|
||||||
|
<tr><td>날짜 → 유닉스 타임스탬프</td><td>$epoch</td><td>2023-11-14 → 1700000000</td></tr>
|
||||||
|
<tr><td>대문자 변환</td><td>$upper</td><td>hello → HELLO</td></tr>
|
||||||
|
<tr><td>소문자 변환</td><td>$lower</td><td>HELLO → hello</td></tr>
|
||||||
|
<tr><td>URL 인코딩</td><td>$urle</td><td>한글 → %ED%95%9C%EA%B8%80</td></tr>
|
||||||
|
<tr><td>URL 디코딩</td><td>$urld</td><td>%ED%95%9C%EA%B8%80 → 한글</td></tr>
|
||||||
|
<tr><td>Base64 인코딩</td><td>$b64e</td><td>text → dGV4dA==</td></tr>
|
||||||
|
<tr><td>Base64 디코딩</td><td>$b64d</td><td>dGV4dA== → text</td></tr>
|
||||||
|
<tr><td>마크다운 → 텍스트</td><td>$md</td><td>**bold** → bold</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>사용자 정의 변환 규칙은 settings.json의 "clipboardTransformers" 배열에 추가하며, 정규식 기반 변환과 외부 스크립트 호출을 지원합니다. 자세한 내용은 섹션 7.4를 참조하십시오.</p>
|
||||||
|
|
||||||
|
<h2><b>3.3 동적 API Alias (#)</b></h2>
|
||||||
|
<p># prefix를 사용하는 Alias는 외부 API를 호출하여 동적 결과를 표시합니다. 각 API 연결은 "apiAdapters" 설정으로 정의합니다.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>항목</b></th><th><b>요구사항</b></th></tr>
|
||||||
|
<tr><td>인증</td><td>Personal Access Token(PAT) 또는 OAuth 2.0. 토큰은 Windows Credential Manager에 저장</td></tr>
|
||||||
|
<tr><td>네트워크 오류</td><td>3초 내 응답 없으면 타임아웃, 오프라인 캐시(최대 1시간) 표시</td></tr>
|
||||||
|
<tr><td>결과 표시</td><td>최대 10개 항목을 런처 결과 리스트에 표시, Enter로 기본 동작(URL 오픈) 실행</td></tr>
|
||||||
|
<tr><td>빌트인 어댑터</td><td>Jira Cloud, GitHub Issues (v1.0). 추가 어댑터는 플러그인으로 제공</td></tr>
|
||||||
|
</table>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>4. UI/UX 디자인 요구사항</b></h1>
|
||||||
|
<h2><b>4.1 런처 윈도우</b></h2>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>요소</b></th><th><b>명세</b></th></tr>
|
||||||
|
<tr><td>형태</td><td>화면 중앙 상단 1/3 지점에 위치하는 반투명 바(Bar) 형태 오버레이</td></tr>
|
||||||
|
<tr><td>기본 크기</td><td>너비: 680px, 높이: 54px (입력 상태). 결과 표시 시 높이 자동 확장</td></tr>
|
||||||
|
<tr><td>투명도</td><td>Opacity 0.96 (기본). settings.json에서 0.7~1.0 조정 가능</td></tr>
|
||||||
|
<tr><td>테마</td><td>시스템 다크/라이트 모드 자동 감지(WMI 또는 레지스트리 감시). 수동 고정 설정 가능</td></tr>
|
||||||
|
<tr><td>폰트</td><td>Segoe UI (영문), Malgun Gothic (한글), 16px</td></tr>
|
||||||
|
<tr><td>애니메이션</td><td>호출: 상단 20px에서 Fade-in + SlideDown (120ms). 닫힘: Fade-out (80ms)</td></tr>
|
||||||
|
<tr><td>항상 최상위</td><td>Topmost = true. 다른 창에 가려지지 않음</td></tr>
|
||||||
|
<tr><td>포커스 처리</td><td>런처 외부 클릭 시 자동 닫힘 (LostFocus 이벤트)</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>4.2 결과 리스트</b></h2>
|
||||||
|
<ul>
|
||||||
|
<li>최대 5~7개 항목 표시 (기본 5개, settings.json에서 조정)</li>
|
||||||
|
<li>각 항목: 아이콘(32x32) + 제목 + 부제목(경로 또는 설명)</li>
|
||||||
|
<li>키보드 탐색: ↑↓ 화살표, Enter로 실행, Esc로 닫기, Tab으로 자동완성</li>
|
||||||
|
<li>마우스 클릭으로도 실행 가능</li>
|
||||||
|
<li>결과 없음 시: "일치하는 항목이 없습니다" 메시지 표시</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><b>4.3 접근성 (Accessibility)</b></h2>
|
||||||
|
<ul>
|
||||||
|
<li>UI Automation(UIA) 속성 제공으로 스크린 리더 지원</li>
|
||||||
|
<li>고대비(High Contrast) 모드 지원</li>
|
||||||
|
<li>글꼴 크기 배율: 시스템 DPI 설정 반영 (100% / 125% / 150% / 200%)</li>
|
||||||
|
<li>Alt+Space 단축키는 settings.json에서 변경 가능</li>
|
||||||
|
</ul>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>5. 비기능 요구사항 (NFR)</b></h1>
|
||||||
|
<h2><b>5.1 성능</b></h2>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>항목</b></th><th><b>목표 수치</b></th><th><b>측정 방법</b></th></tr>
|
||||||
|
<tr><td>Fuzzy 검색 응답</td><td>< 100ms (p95)</td><td>로컬 인덱스 10,000건 기준 자동화 벤치마크</td></tr>
|
||||||
|
<tr><td>Instant Restore (5창 기준)</td><td>< 1.5초</td><td>스톱워치 측정, 5회 평균</td></tr>
|
||||||
|
<tr><td>앱 시작 시간</td><td>< 800ms (백그라운드 Ready 상태)</td><td>프로세스 시작 → 트레이 아이콘 표시까지</td></tr>
|
||||||
|
<tr><td>메모리 사용량</td><td>유휴 시 < 80MB RSS</td><td>Process Explorer 모니터링</td></tr>
|
||||||
|
<tr><td>CPU 점유율</td><td>유휴 시 < 0.5%</td><td>10분 유휴 후 평균</td></tr>
|
||||||
|
<tr><td>인덱싱 시간</td><td>10,000파일 < 3초</td><td>초기 기동 시 측정</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>5.2 신뢰성 & 안정성</b></h2>
|
||||||
|
<ul>
|
||||||
|
<li>Global Hook 스레드 예외 시 자동 재등록 (최대 3회 재시도, 이후 트레이 경고 알림)</li>
|
||||||
|
<li>앱 크래시 시 Windows Error Reporting 연동 및 로컬 크래시 덤프 저장 (%APPDATA%\OLEDiCommander\crashes\)</li>
|
||||||
|
<li>settings.json 파싱 실패 시 기본값(default) 설정으로 폴백, 원본 파일은 .bak 확장자로 백업</li>
|
||||||
|
<li>MTBF(평균 무고장 시간) 목표: 7일 연속 사용 시 크래시 없음</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><b>5.3 보안</b></h2>
|
||||||
|
<ul>
|
||||||
|
<li>Global Keyboard Hook(WH_KEYBOARD_LL): 키 입력을 로깅하지 않음. Alt+Space 패턴 감지 후 즉시 버퍼 파기</li>
|
||||||
|
<li>API 토큰: Windows Credential Manager(DPAPI) 저장, settings.json에 평문 토큰 기록 금지</li>
|
||||||
|
<li>플러그인 .dll: 디지털 서명 검증 권장 (v1.0에서는 경고 표시, v2.0에서 강제 서명 요구 예정)</li>
|
||||||
|
<li>UAC: 앱 자체는 일반 사용자 권한으로 실행. 관리자 권한이 필요한 동작 시 명시적 UAC 프롬프트</li>
|
||||||
|
<li>네트워크 통신: HTTPS only (TLS 1.2+). 자체 서명 인증서 거부</li>
|
||||||
|
</ul>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>보안 주의사항 – Windows Defender / EDR 탐지</b><br/>WH_KEYBOARD_LL 훅은 일부 보안 소프트웨어에서 키로거로 오탐될 수 있습니다.<br/>대응 방안: 앱 배포 시 코드 서명 인증서 적용, Microsoft Store 등록 검토.<br/>기업 환경 배포 시에는 GPO 화이트리스트 등록 가이드를 별도 제공합니다.</th></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>5.4 유지보수성</b></h2>
|
||||||
|
<ul>
|
||||||
|
<li>모듈 간 의존성: DI 컨테이너(Microsoft.Extensions.DependencyInjection) 사용</li>
|
||||||
|
<li>로깅: Serilog 사용, 레벨(DEBUG/INFO/WARN/ERROR) 설정 가능. 로그 파일: %APPDATA%\OLEDiCommander\logs\</li>
|
||||||
|
<li>단위 테스트 커버리지: 핵심 모듈(CommandResolver, FuzzyEngine) 80% 이상 목표</li>
|
||||||
|
<li>업데이트: Squirrel.Windows 또는 MSIX 패키지 업데이트 채널 사용</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><b>5.5 호환성</b></h2>
|
||||||
|
<ul>
|
||||||
|
<li>최소 지원 OS: Windows 10 (버전 1903, 빌드 18362) 이상</li>
|
||||||
|
<li>권장 OS: Windows 11</li>
|
||||||
|
<li>.NET 런타임: .NET 8.0 (Self-contained 배포로 별도 설치 불필요)</li>
|
||||||
|
<li>DPI 지원: System DPI 및 Per-Monitor DPI v2 (WPF DPI 자동 스케일링)</li>
|
||||||
|
<li>멀티 모니터: 동일 DPI 및 혼합 DPI 환경 모두 지원</li>
|
||||||
|
</ul>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>6. 예외 처리 및 엣지 케이스</b></h1>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>시나리오</b></th><th><b>원인</b></th><th><b>처리 방침</b></th></tr>
|
||||||
|
<tr><td>Restore 시 앱 미실행</td><td>저장된 EXE가 닫혀 있음</td><td>자동 EXE 실행 → 3초 대기 → 실패 시 건너뜀, 결과 알림</td></tr>
|
||||||
|
<tr><td>모니터 구성 변경</td><td>모니터 추가/제거/해상도 변경</td><td>settings.json의 "monitorMismatch" 정책에 따라 fit/skip/warn</td></tr>
|
||||||
|
<tr><td>단축키 충돌</td><td>타 앱이 Alt+Space 선점</td><td>등록 실패 감지 → 트레이에 경고 → 대체 단축키 제안</td></tr>
|
||||||
|
<tr><td>관리자 권한 창 제어</td><td>타 프로세스가 elevated</td><td>SetWindowPos 예외 캐치 → 해당 창 건너뜀, 로그 기록</td></tr>
|
||||||
|
<tr><td>settings.json 손상</td><td>JSON 파싱 오류</td><td>원본 .bak 저장 → 기본값 로드 → 복구 안내 메시지</td></tr>
|
||||||
|
<tr><td>Alias 중복 등록</td><td>동일 키워드 중복</td><td>나중에 추가된 항목이 우선. 경고 로그 기록</td></tr>
|
||||||
|
<tr><td>플러그인 로드 실패</td><td>.dll 서명 불일치 또는 예외</td><td>해당 플러그인 건너뜀, 오류 로그. 앱은 계속 실행</td></tr>
|
||||||
|
<tr><td>API 타임아웃</td><td>네트워크 불안정</td><td>3초 타임아웃 → 오프라인 캐시 표시 (1시간 유효) → 캐시 없으면 오류 메시지</td></tr>
|
||||||
|
<tr><td>앱 인덱스 폴더 접근 불가</td><td>권한 없는 폴더</td><td>해당 폴더 스킵, 인덱싱 완료 후 경고 로그</td></tr>
|
||||||
|
<tr><td>Fuzzy 검색 결과 없음</td><td>입력에 일치 항목 없음</td><td>"일치하는 항목이 없습니다" 표시, 입력 지속 허용</td></tr>
|
||||||
|
</table>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>7. 데이터 스키마 (settings.json)</b></h1>
|
||||||
|
<p>모든 사용자 설정과 Profile, Alias는 단일 JSON 파일로 관리됩니다. 파일 위치: %APPDATA%\OLEDiCommander\settings.json</p>
|
||||||
|
|
||||||
|
<p>{</p>
|
||||||
|
<p> "version": "1.0",</p>
|
||||||
|
<p> "hotkey": "Alt+Space",</p>
|
||||||
|
<p> "launcher": {</p>
|
||||||
|
<p> "opacity": 0.96,</p>
|
||||||
|
<p> "maxResults": 7,</p>
|
||||||
|
<p> "theme": "system",</p>
|
||||||
|
<p> "position": "center-top"</p>
|
||||||
|
<p> },</p>
|
||||||
|
<p> "indexPaths": [</p>
|
||||||
|
<p> "%USERPROFILE%\\Desktop",</p>
|
||||||
|
<p> "%APPDATA%\\Microsoft\\Windows\\Start Menu"</p>
|
||||||
|
<p> ],</p>
|
||||||
|
<p> "monitorMismatch": "warn",</p>
|
||||||
|
<p> "profiles": [</p>
|
||||||
|
<p> {</p>
|
||||||
|
<p> "name": "dev",</p>
|
||||||
|
<p> "windows": [</p>
|
||||||
|
<p> {</p>
|
||||||
|
<p> "exe": "C:\\Program Files\\Microsoft VS Code\\Code.exe",</p>
|
||||||
|
<p> "title": "Visual Studio Code",</p>
|
||||||
|
<p> "rect": { "x": 0, "y": 0, "width": 1280, "height": 1080 },</p>
|
||||||
|
<p> "showCmd": "Normal",</p>
|
||||||
|
<p> "monitor": 0</p>
|
||||||
|
<p> }</p>
|
||||||
|
<p> ]</p>
|
||||||
|
<p> }</p>
|
||||||
|
<p> ],</p>
|
||||||
|
<p> "aliases": [</p>
|
||||||
|
<p> { "key": "@blog", "type": "url", "target": "https://swarchitect.net/admin" },</p>
|
||||||
|
<p> { "key": "#jira", "type": "api", "adapter": "jira", "query": "assignee=currentUser() ORDER BY updated DESC" },</p>
|
||||||
|
<p> { "key": "~proj", "type": "folder", "target": "C:\\Dev\\Projects" },</p>
|
||||||
|
<p> { "key": ">build", "type": "batch", "target": "cmd /c C:\\Dev\\build.bat", "showWindow": false }</p>
|
||||||
|
<p> ],</p>
|
||||||
|
<p> "clipboardTransformers": [</p>
|
||||||
|
<p> { "key": "$myRule", "type": "regex", "pattern": "(\\d{4})-(\\d{2})-(\\d{2})", "replace": "$3/$2/$1" }</p>
|
||||||
|
<p> ],</p>
|
||||||
|
<p> "apiAdapters": [</p>
|
||||||
|
<p> { "id": "jira", "baseUrl": "https://yourorg.atlassian.net", "credentialKey": "jira_pat" }</p>
|
||||||
|
<p> ],</p>
|
||||||
|
<p> "plugins": [</p>
|
||||||
|
<p> { "path": "C:\\OLEDiPlugins\\MyPlugin.dll", "enabled": true }</p>
|
||||||
|
<p> ]</p>
|
||||||
|
<p>}</p>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>8. 개발자 확장 가이드 (Plugin & Skill Development)</b></h1>
|
||||||
|
<p>이 섹션은 OLEDi Commander에 새로운 기능, 명령어, API 연결, 변환 규칙을 추가하려는 개발자를 위한 문서입니다. 확장 방법은 세 가지 경로로 제공됩니다.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>확장 방법</b></th><th><b>난이도</b></th><th><b>추천 대상</b></th></tr>
|
||||||
|
<tr><td>settings.json 수정</td><td>쉬움</td><td>URL Alias, 폴더 단축키, 배치 명령 추가</td></tr>
|
||||||
|
<tr><td>JSON 스킬 파일 (.skill.json)</td><td>보통</td><td>API 어댑터, 커스텀 변환 규칙</td></tr>
|
||||||
|
<tr><td>.dll 플러그인 (C# IActionHandler)</td><td>어려움</td><td>완전히 새로운 명령 타입, UI 커스터마이징</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>8.1 settings.json으로 Alias 추가하기</b></h2>
|
||||||
|
<p>가장 간단한 확장 방법입니다. settings.json 파일을 텍스트 에디터로 열어 "aliases" 배열에 항목을 추가합니다.</p>
|
||||||
|
|
||||||
|
<p>// URL 열기 Alias 추가</p>
|
||||||
|
<p>{ "key": "@notion", "type": "url", "target": "https://notion.so/your-workspace" }</p>
|
||||||
|
|
||||||
|
<p>// 폴더 열기 Alias 추가</p>
|
||||||
|
<p>{ "key": "~dl", "type": "folder", "target": "%USERPROFILE%\\Downloads" }</p>
|
||||||
|
|
||||||
|
<p>// 배치 파일 실행 Alias 추가 (출력 창 표시)</p>
|
||||||
|
<p>{ "key": ">deploy", "type": "batch", "target": "cmd /c C:\\deploy.bat", "showWindow": true }</p>
|
||||||
|
|
||||||
|
<p>// 배치 파일 실행 Alias 추가 (백그라운드 실행)</p>
|
||||||
|
<p>{ "key": ">silent", "type": "batch", "target": "powershell -File C:\\task.ps1", "showWindow": false }</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>팁: 환경변수 사용</b><br/>"target" 값에 %USERPROFILE%, %APPDATA%, %TEMP% 등 Windows 환경변수를 사용할 수 있습니다.<br/>앱 실행 시 자동으로 확장됩니다.</th></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>8.2 Clipboard Transformer 규칙 추가하기</b></h2>
|
||||||
|
<p>settings.json의 "clipboardTransformers" 배열에 변환 규칙을 추가합니다. 정규식(regex) 또는 외부 스크립트(script) 타입을 지원합니다.</p>
|
||||||
|
|
||||||
|
<p>// 정규식 변환: 날짜 형식 YYYY-MM-DD → DD/MM/YYYY</p>
|
||||||
|
<p>{</p>
|
||||||
|
<p> "key": "$date",</p>
|
||||||
|
<p> "type": "regex",</p>
|
||||||
|
<p> "pattern": "(\\d{4})-(\\d{2})-(\\d{2})",</p>
|
||||||
|
<p> "replace": "$3/$2/$1",</p>
|
||||||
|
<p> "description": "ISO 날짜를 로컬 날짜 형식으로 변환"</p>
|
||||||
|
<p>}</p>
|
||||||
|
|
||||||
|
<p>// PowerShell 스크립트 호출 변환</p>
|
||||||
|
<p>{</p>
|
||||||
|
<p> "key": "$ps",</p>
|
||||||
|
<p> "type": "script",</p>
|
||||||
|
<p> "command": "powershell -NoProfile -Command \"$input | ConvertTo-Json\"",</p>
|
||||||
|
<p> "timeout": 5000,</p>
|
||||||
|
<p> "description": "클립보드 텍스트를 PowerShell로 처리"</p>
|
||||||
|
<p>}</p>
|
||||||
|
|
||||||
|
<p>스크립트 타입의 경우, 앱은 클립보드 텍스트를 stdin으로 전달하고 stdout 결과를 클립보드에 저장합니다. timeout(ms) 초과 시 원본 텍스트를 유지합니다.</p>
|
||||||
|
|
||||||
|
<h2><b>8.3 JSON 스킬 파일로 API Adapter 추가하기</b></h2>
|
||||||
|
<p>새로운 API 서비스(예: Notion, Linear, Slack)를 연결하려면 .skill.json 파일을 작성합니다. 파일은 %APPDATA%\OLEDiCommander\skills\ 폴더에 저장합니다.</p>
|
||||||
|
|
||||||
|
<p>// %APPDATA%\OLEDiCommander\skills\notion.skill.json</p>
|
||||||
|
<p>{</p>
|
||||||
|
<p> "id": "notion",</p>
|
||||||
|
<p> "name": "Notion 페이지 검색",</p>
|
||||||
|
<p> "version": "1.0",</p>
|
||||||
|
<p> "prefix": "#notion",</p>
|
||||||
|
<p> "credential": {</p>
|
||||||
|
<p> "type": "bearer_token",</p>
|
||||||
|
<p> "credentialKey": "notion_api_token"</p>
|
||||||
|
<p> },</p>
|
||||||
|
<p> "request": {</p>
|
||||||
|
<p> "method": "POST",</p>
|
||||||
|
<p> "url": "https://api.notion.com/v1/search",</p>
|
||||||
|
<p> "headers": { "Notion-Version": "2022-06-28" },</p>
|
||||||
|
<p> "body": { "query": "{{INPUT}}", "page_size": 10 }</p>
|
||||||
|
<p> },</p>
|
||||||
|
<p> "response": {</p>
|
||||||
|
<p> "resultsPath": "results",</p>
|
||||||
|
<p> "titleField": "properties.title.title[0].plain_text",</p>
|
||||||
|
<p> "subtitleField": "url",</p>
|
||||||
|
<p> "actionUrl": "url"</p>
|
||||||
|
<p> },</p>
|
||||||
|
<p> "cache": { "ttl": 300 }</p>
|
||||||
|
<p>}</p>
|
||||||
|
|
||||||
|
<p>{{INPUT}}은 사용자가 # 이후에 입력한 텍스트로 치환됩니다. 토큰은 앱 내 설정 화면에서 입력하며 Windows Credential Manager에 암호화 저장됩니다.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>필드</b></th><th><b>필수</b></th><th><b>설명</b></th></tr>
|
||||||
|
<tr><td>id</td><td>예</td><td>스킬 고유 식별자 (영문 소문자, 하이픈 허용)</td></tr>
|
||||||
|
<tr><td>prefix</td><td>예</td><td>런처에서 이 스킬을 호출하는 명령어 (예: #notion)</td></tr>
|
||||||
|
<tr><td>credential.type</td><td>예</td><td>bearer_token / basic_auth / oauth2 중 선택</td></tr>
|
||||||
|
<tr><td>request.url</td><td>예</td><td>API 엔드포인트. {{INPUT}}, {{TOKEN}} 템플릿 변수 사용 가능</td></tr>
|
||||||
|
<tr><td>response.resultsPath</td><td>예</td><td>JSON 응답에서 결과 배열 경로 (dot notation)</td></tr>
|
||||||
|
<tr><td>response.actionUrl</td><td>예</td><td>Enter 시 열리는 URL 필드 경로</td></tr>
|
||||||
|
<tr><td>cache.ttl</td><td>아니오</td><td>결과 캐시 유효 시간(초). 기본값 0 (캐시 없음)</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>8.4 C# .dll 플러그인으로 새 ActionHandler 개발하기</b></h2>
|
||||||
|
<p>완전히 새로운 명령 타입, 복잡한 UI, 또는 OS 레벨 기능이 필요한 경우 C# 플러그인을 개발합니다.</p>
|
||||||
|
|
||||||
|
<h3><b>8.4.1 인터페이스 정의</b></h3>
|
||||||
|
<p>// OLEDiCommander.SDK NuGet 패키지 설치 후 사용</p>
|
||||||
|
<p>using OLEDiCommander.SDK;</p>
|
||||||
|
|
||||||
|
<p>/// <summary></p>
|
||||||
|
<p>/// 모든 플러그인은 이 인터페이스를 구현해야 합니다.</p>
|
||||||
|
<p>/// </summary></p>
|
||||||
|
<p>public interface IActionHandler</p>
|
||||||
|
<p>{</p>
|
||||||
|
<p> // 이 핸들러가 처리할 prefix (예: "@", "#", "!") 또는 null (Fuzzy 결과에만 등록)</p>
|
||||||
|
<p> string? Prefix { get; }</p>
|
||||||
|
|
||||||
|
<p> // 런처 결과 리스트에 표시할 항목을 반환합니다.</p>
|
||||||
|
<p> // query: prefix 이후의 입력 텍스트</p>
|
||||||
|
<p> Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct);</p>
|
||||||
|
|
||||||
|
<p> // 사용자가 항목을 선택(Enter)했을 때 실행됩니다.</p>
|
||||||
|
<p> Task ExecuteAsync(LauncherItem item, CancellationToken ct);</p>
|
||||||
|
|
||||||
|
<p> // 플러그인 메타데이터</p>
|
||||||
|
<p> PluginMetadata Metadata { get; }</p>
|
||||||
|
<p>}</p>
|
||||||
|
|
||||||
|
<p>public record LauncherItem(</p>
|
||||||
|
<p> string Title,</p>
|
||||||
|
<p> string Subtitle,</p>
|
||||||
|
<p> string? IconPath, // null이면 기본 아이콘 사용</p>
|
||||||
|
<p> object? Data // ExecuteAsync에 전달되는 임의 데이터</p>
|
||||||
|
<p>);</p>
|
||||||
|
|
||||||
|
<p>public record PluginMetadata(</p>
|
||||||
|
<p> string Id,</p>
|
||||||
|
<p> string Name,</p>
|
||||||
|
<p> string Version,</p>
|
||||||
|
<p> string Author</p>
|
||||||
|
<p>);</p>
|
||||||
|
|
||||||
|
<h3><b>8.4.2 예제: 계산기 플러그인</b></h3>
|
||||||
|
<p>using OLEDiCommander.SDK;</p>
|
||||||
|
<p>using System.Data;</p>
|
||||||
|
|
||||||
|
<p>[Export(typeof(IActionHandler))]</p>
|
||||||
|
<p>public class CalculatorHandler : IActionHandler</p>
|
||||||
|
<p>{</p>
|
||||||
|
<p> public string? Prefix => "="; // "=2+3" 입력 시 이 핸들러 호출</p>
|
||||||
|
|
||||||
|
<p> public PluginMetadata Metadata => new("calculator", "계산기", "1.0", "YourName");</p>
|
||||||
|
|
||||||
|
<p> public async Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)</p>
|
||||||
|
<p> {</p>
|
||||||
|
<p> try</p>
|
||||||
|
<p> {</p>
|
||||||
|
<p> var result = new DataTable().Compute(query, null);</p>
|
||||||
|
<p> return [new LauncherItem($"= {result}", "Enter로 복사", null, result.ToString())];</p>
|
||||||
|
<p> }</p>
|
||||||
|
<p> catch</p>
|
||||||
|
<p> {</p>
|
||||||
|
<p> return [new LauncherItem("수식 오류", "올바른 수식을 입력하세요", null, null)];</p>
|
||||||
|
<p> }</p>
|
||||||
|
<p> }</p>
|
||||||
|
|
||||||
|
<p> public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)</p>
|
||||||
|
<p> {</p>
|
||||||
|
<p> if (item.Data is string val)</p>
|
||||||
|
<p> Clipboard.SetText(val); // 결과를 클립보드에 복사</p>
|
||||||
|
<p> }</p>
|
||||||
|
<p>}</p>
|
||||||
|
|
||||||
|
<h3><b>8.4.3 플러그인 배포 및 등록</b></h3>
|
||||||
|
<ul>
|
||||||
|
<li>프로젝트를 빌드하여 MyPlugin.dll 생성</li>
|
||||||
|
<li>.dll을 임의 폴더에 저장 (예: C:\\OLEDiPlugins\\MyPlugin.dll)</li>
|
||||||
|
<li>settings.json의 "plugins" 배열에 경로 등록:</li>
|
||||||
|
</ul>
|
||||||
|
<p>{ "path": "C:\\OLEDiPlugins\\MyPlugin.dll", "enabled": true }</p>
|
||||||
|
<ul>
|
||||||
|
<li>OLEDi Commander 재시작 → 시스템 트레이 아이콘 우클릭 → "플러그인 재로드"</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>개발 팁: 핫 리로드</b><br/>개발 중에는 시스템 트레이 → "개발자 모드" 활성화 시 플러그인 파일 변경 감지 후 자동 재로드됩니다.<br/>OLEDiCommander.SDK.dll은 NuGet 패키지(OLEDiCommander.SDK)로 배포됩니다.<br/>단위 테스트 시 MockLauncherContext를 주입하여 UI 없이 IActionHandler를 테스트할 수 있습니다.</th></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h2><b>8.5 확장 체크리스트</b></h2>
|
||||||
|
<p>새 기능을 추가하기 전에 아래 항목을 확인하십시오.</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th><b>체크 항목</b></th><th><b>확인 기준</b></th></tr>
|
||||||
|
<tr><td>Prefix 충돌 확인</td><td>기존 Prefix 테이블(섹션 2.2)과 중복 없는지 확인</td></tr>
|
||||||
|
<tr><td>에러 처리</td><td>네트워크 오류, 타임아웃, null 결과 등 모든 예외 처리 구현</td></tr>
|
||||||
|
<tr><td>CancellationToken 사용</td><td>사용자가 ESC 입력 시 진행 중인 비동기 작업 즉시 취소</td></tr>
|
||||||
|
<tr><td>캐싱 고려</td><td>API 호출 결과는 TTL 캐시 적용으로 불필요한 네트워크 요청 방지</td></tr>
|
||||||
|
<tr><td>로깅 추가</td><td>ILogger<T>를 통해 DEBUG/ERROR 레벨 로그 기록</td></tr>
|
||||||
|
<tr><td>단위 테스트</td><td>GetItemsAsync, ExecuteAsync 각각 최소 1개 이상 테스트 케이스 작성</td></tr>
|
||||||
|
<tr><td>아이콘 제공</td><td>32x32 PNG 아이콘을 LauncherItem.IconPath에 포함</td></tr>
|
||||||
|
<tr><td>설명 작성</td><td>PluginMetadata.Name, settings.json의 description 필드 작성</td></tr>
|
||||||
|
</table>
|
||||||
|
<p><br/></p>
|
||||||
|
<h1><b>9. 설치 및 배포</b></h1>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>항목</b></th><th><b>내용</b></th></tr>
|
||||||
|
<tr><td>배포 형태</td><td>MSIX 패키지 (Microsoft Store) 또는 Squirrel.Windows 인스톨러 (.exe)</td></tr>
|
||||||
|
<tr><td>Self-contained</td><td>.NET 8 Self-contained 배포 – 별도 런타임 설치 불필요</td></tr>
|
||||||
|
<tr><td>설치 경로</td><td>%LOCALAPPDATA%\Programs\OLEDiCommander\</td></tr>
|
||||||
|
<tr><td>설정 경로</td><td>%APPDATA%\OLEDiCommander\</td></tr>
|
||||||
|
<tr><td>자동 시작</td><td>HKCU Run 레지스트리 키 등록 (설치 시 옵션 선택)</td></tr>
|
||||||
|
<tr><td>자동 업데이트</td><td>앱 실행 시 GitHub Releases API 버전 확인, 백그라운드 다운로드</td></tr>
|
||||||
|
<tr><td>제거</td><td>일반 "앱 및 기능"으로 제거 가능. 설정 파일 유지 여부 선택</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h1><b>10. 미결 사항 및 향후 계획 (v2.0)</b></h1>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>항목</b></th><th><b>우선순위</b></th><th><b>비고</b></th></tr>
|
||||||
|
<tr><td>플러그인 마켓플레이스 UI</td><td>높음</td><td>서드파티 스킬 검색/설치/업데이트 통합 UI</td></tr>
|
||||||
|
<tr><td>OAuth 2.0 인증 흐름</td><td>높음</td><td>GitHub, Google 등 OAuth 기반 API 어댑터 지원</td></tr>
|
||||||
|
<tr><td>AI 자연어 명령</td><td>중간</td><td>예: "1주일 전 내 Jira 티켓 열어줘" → #jira 쿼리 자동 생성</td></tr>
|
||||||
|
<tr><td>클라우드 설정 동기화</td><td>중간</td><td>OneDrive / iCloud Drive를 통한 settings.json 동기화</td></tr>
|
||||||
|
<tr><td>플러그인 서명 강제화</td><td>높음</td><td>v2.0부터 서명 없는 .dll 실행 차단</td></tr>
|
||||||
|
<tr><td>스크립트 언어 지원</td><td>낮음</td><td>Python / Node.js 스크립트를 스킬로 직접 등록</td></tr>
|
||||||
|
<tr><td>음성 명령 입력</td><td>낮음</td><td>Windows Speech API 연동</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h1><b>변경 이력</b></h1>
|
||||||
|
<table>
|
||||||
|
<tr><th><b>버전</b></th><th><b>날짜</b></th><th><b>작성자</b></th><th><b>변경 내용</b></th></tr>
|
||||||
|
<tr><td>v1.0</td><td>2026-03-21</td><td>—</td><td>초안 작성 (SRS 전체 구조 + 개발자 확장 가이드 포함)</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class='footer'>Converted from: AXCommander_SRS_v1.0.docx</p>
|
||||||
|
</body></html>
|
||||||
39
AxCopilot.sln
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 18
|
||||||
|
VisualStudioVersion = 18.2.11415.280 d18.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AxCopilot", "src\AxCopilot\AxCopilot.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AxCopilot.SDK", "src\AxCopilot.SDK\AxCopilot.SDK.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AxCopilot.Tests", "src\AxCopilot.Tests\AxCopilot.Tests.csproj", "{C3D4E5F6-A7B8-9012-CDEF-123456789012}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AxKeyEncryptor", "src\AxKeyEncryptor\AxKeyEncryptor.csproj", "{D4E5F6A7-B8C9-0123-DEFA-234567890123}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B2C3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C3D4E5F6-A7B8-9012-CDEF-123456789012}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D4E5F6A7-B8C9-0123-DEFA-234567890123}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D4E5F6A7-B8C9-0123-DEFA-234567890123}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D4E5F6A7-B8C9-0123-DEFA-234567890123}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D4E5F6A7-B8C9-0123-DEFA-234567890123}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
755
CLAUDE.md
Normal file
@@ -0,0 +1,755 @@
|
|||||||
|
# AX Copilot 개발 지시사항
|
||||||
|
|
||||||
|
이 파일은 모든 개발 세션에서 일관된 품질의 결과물을 보장하기 위한 필수 지시사항입니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. UI/UX 디자인 원칙
|
||||||
|
|
||||||
|
### 기본 컨트롤 사용 금지
|
||||||
|
- **ContextMenu, MenuItem** 사용 금지 → 커스텀 `Popup` (Border + MouseLeftButtonUp, 12px 라운드, 호버, 드롭섀도)
|
||||||
|
- **MessageBox** 사용 금지 → `CustomMessageBox.Show()` 사용
|
||||||
|
- **기본 CheckBox** 사용 금지 → `Style="{StaticResource ToggleSwitch}"` 좌우 슬라이드 토글
|
||||||
|
- **Popup 내부에 Button** 사용 금지 → `Border` + `MouseLeftButtonUp` 패턴 (포커스 캡처 방지)
|
||||||
|
- 수평 스크롤바 금지 → `WrapPanel` 자동 줄바꿈
|
||||||
|
|
||||||
|
### 테마 통일성
|
||||||
|
- 색상 하드코딩 금지 — XAML: `{DynamicResource PrimaryText}`, 코드비하인드: `TryFindResource("PrimaryText") as Brush ?? Brushes.White`
|
||||||
|
- 모든 UI 요소는 현재 적용된 테마 리소스(`LauncherBackground`, `ItemBackground`, `AccentColor`, `PrimaryText`, `SecondaryText` 등)를 사용
|
||||||
|
- 다크 테마 6종 모두에서 텍스트 가독성 확인 필수
|
||||||
|
|
||||||
|
### 코드비하인드 팝업/다이얼로그 테마 규칙
|
||||||
|
- **코드비하인드에서 생성하는 모든 팝업 Window/다이얼로그**도 현재 테마를 따라야 함
|
||||||
|
- 배경: `TryFindResource("LauncherBackground")`, 텍스트: `TryFindResource("PrimaryText")`, 보조 텍스트: `TryFindResource("SecondaryText")`
|
||||||
|
- 테두리: `TryFindResource("BorderColor")`, 아이템 배경: `TryFindResource("ItemBackground")`, 액센트: `TryFindResource("AccentColor")`
|
||||||
|
- 호버 효과 배경: `TryFindResource("ItemHoverBackground")`
|
||||||
|
- `#1A1B2E`, `Brushes.White` 등 고정 색상을 팝업에 직접 사용하는 것은 **금지** — 라이트/다크 테마 전환 시 색상 불일치 발생
|
||||||
|
- 팝업 Window에 테마 적용 패턴:
|
||||||
|
```csharp
|
||||||
|
// 팝업 생성 후 부모 창의 Resources를 팝업에 전달
|
||||||
|
popup.Resources.MergedDictionaries.Add(this.Resources);
|
||||||
|
// 또는 직접 리소스 조회
|
||||||
|
var bg = TryFindResource("LauncherBackground") as Brush ?? Brushes.White;
|
||||||
|
var fg = TryFindResource("PrimaryText") as Brush ?? Brushes.Black;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 인터랙티브 요소
|
||||||
|
- 클릭 가능 영역 최소 36px, FontSize 최소 12px, Padding 최소 6px
|
||||||
|
- 호버/클릭 효과 필수 — `#18FFFFFF` 반투명 배경 + 핸드 커서
|
||||||
|
- 팝업은 `PopupAnimation="Fade"` 기본 적용
|
||||||
|
- 메뉴 항목 FontSize 13px 이상
|
||||||
|
|
||||||
|
### 아이콘 색상
|
||||||
|
- Segoe MDL2 Assets 아이콘은 가능한 한 **의미에 맞는 색상**을 적용 (단색 `SecondaryText` 지양)
|
||||||
|
- 메뉴 항목: 아이콘 + 라벨에 동일 색상 적용 (예: Ask=파랑, Auto=앰버, Deny=빨강)
|
||||||
|
- 하단 바: 각 버튼 아이콘에 기능별 색상 (포맷=보라, 파일=앰버, 권한=파랑, 데이터=녹색)
|
||||||
|
- 활성 상태 항목: `AccentColor` 또는 해당 기능 고유 색상으로 강조
|
||||||
|
|
||||||
|
### 설정 UI 패턴
|
||||||
|
- 켜기/끄기: ToggleSwitch 스타일 (Grid 좌: 라벨, 우: 토글)
|
||||||
|
- 선택형: 커스텀 Popup 드롭다운 (`[라벨: 현재값 ▾]`)
|
||||||
|
- AI/고급 설정 항목 옆에 `?` 도움말 아이콘 + 커스텀 다크 툴팁 (`HelpTooltipStyle`)
|
||||||
|
- 설정 저장 시 `CustomMessageBox`로 완료 알림
|
||||||
|
|
||||||
|
### 헬프 화면 (HelpDetailWindow) 규칙
|
||||||
|
- **버전 정보 금지** — 헬프에 버전별 신기능(예: "v1.6.0 신기능") 항목을 넣지 않으며, 앞으로도 추가하지 않음
|
||||||
|
- **영역별 핵심 기능만 표시** — 개요, AI, 업무 보조 등 영역별로 사용자가 "무엇을 할 수 있는지"만 간결히 설명
|
||||||
|
- **기술 보호 (IP 보호)** — 설명에서 내부 기술·구현 방식을 유추할 수 없어야 함. 아래 용어를 헬프에 직접 노출하는 것은 **금지**:
|
||||||
|
|
||||||
|
| 사용 금지 (내부 기술) | 대신 사용 (사용자 관점) |
|
||||||
|
|---------------------|----------------------|
|
||||||
|
| SSE, Server-Sent Events | "실시간 응답" |
|
||||||
|
| AES-256-GCM, DPAPI, 암호화 알고리즘명 | "암호화 저장", "안전하게 보호" |
|
||||||
|
| OpenXML, python-docx, openpyxl | "문서 생성", "파일 생성" |
|
||||||
|
| MCP, JSON-RPC, stdio | "외부 도구 연결" |
|
||||||
|
| LINQ, TF-IDF, LCS, Mustache | 기능 설명으로 대체 |
|
||||||
|
| Ollama, vLLM, Gemini, Claude (모델명) | "AI 서비스", "AI 모델" |
|
||||||
|
| OWASP, CVE | "보안 점검", "취약점 분석" |
|
||||||
|
| system_prompt.txt, 클래스명, 파일명 | 기능 설명으로 대체 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 설정값 관리 원칙
|
||||||
|
|
||||||
|
### 신규 기능 → 설정 검토 필수
|
||||||
|
신규 기능 추가 시 사용자/개발자가 제어할 수 있는 설정값을 반드시 검토하고 추가합니다:
|
||||||
|
1. `AppSettings.cs`에 프로퍼티 + JsonPropertyName + 기본값 추가
|
||||||
|
2. `SettingsViewModel.cs`에 바인딩 프로퍼티 + Load/Save 매핑
|
||||||
|
3. `SettingsWindow.xaml`에 적절한 탭에 UI 컨트롤 배치
|
||||||
|
4. 도구(Tool) 클래스에서 설정값을 실제로 체크하여 동작에 반영
|
||||||
|
|
||||||
|
### Cowork / Code 설정 분리 원칙
|
||||||
|
에이전트 동작 설정은 **공통(LlmSettings)에 넣지 말고, Cowork/Code 각각에 배치**합니다:
|
||||||
|
- **Cowork 전용 설정**: `LlmSettings`에 직접 프로퍼티 추가 → SettingsWindow의 `AgentPanelCowork` 패널에 배치
|
||||||
|
- **Code 전용 설정**: `CodeSettings` 클래스에 프로퍼티 추가 → SettingsWindow의 `AgentPanelCode` 패널에 배치. XAML 바인딩은 `{Binding Code.PropertyName}`
|
||||||
|
- **진짜 공통인 경우만** `AgentPanelCoworkCode` 패널에 배치 (예: MaxAgentIterations, MaxRetryOnError)
|
||||||
|
- 검증 강제, 출력 형식, 폴더 데이터 활용 등 **탭마다 다르게 동작하는 기능**은 반드시 분리
|
||||||
|
- AgentLoopService에서 `ActiveTab == "Code"` 분기로 탭별 설정 참조
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 탭별 설정 참조 패턴
|
||||||
|
var shouldVerify = ActiveTab == "Code"
|
||||||
|
? llm.Code.EnableCodeVerification
|
||||||
|
: llm.EnableCoworkVerification;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 설정값이 코드에서 실제 동작해야 함
|
||||||
|
설정을 정의만 하고 코드에서 읽지 않는 것은 금지. 설정 체크 패턴:
|
||||||
|
```csharp
|
||||||
|
var app = System.Windows.Application.Current as App;
|
||||||
|
var enabled = app?.SettingsService?.Settings.Llm.Code.EnableLsp ?? true;
|
||||||
|
if (!enabled) return ToolResult.Ok("비활성 상태입니다. 설정에서 활성화하세요.");
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 버전 관리 및 배포
|
||||||
|
|
||||||
|
### 버전 번호 규칙
|
||||||
|
- **소규모 배포** (버그 수정, 설정 추가, UI 개선): `+0.0.1` (예: 1.4.0 → 1.4.1)
|
||||||
|
- **대규모 기능 배포** (Phase 완료, 새 에이전트 도구, 핵심 기능): `+0.1.0` (예: 1.4.0 → 1.5.0)
|
||||||
|
|
||||||
|
### 버전 변경 시 반드시 수정할 파일 (체크리스트)
|
||||||
|
|
||||||
|
| # | 대상 | 파일 경로 | 수정 내용 |
|
||||||
|
|---|------|----------|----------|
|
||||||
|
| 1 | 앱 버전 | `src/AxCopilot/AxCopilot.csproj` → `<Version>` | 버전 번호 |
|
||||||
|
| 2 | 인스톨러 프로젝트 | `src/AxCopilot.Installer/AxCopilot.Installer.csproj` → `<Version>` | 동일 |
|
||||||
|
| 3 | 인스톨러 표시 | `src/AxCopilot.Installer/SetupForm.cs` → `AppVer` | 동일 |
|
||||||
|
| 4 | MCP 클라이언트 | `src/AxCopilot/Services/McpClientService.cs` → `clientInfo.version` | 동일 |
|
||||||
|
| 5 | 개발자 가이드 | `src/AxCopilot/Assets/AX Copilot 개발자가이드.htm` | 버전 이력 항목 추가만 (**헤더/푸터에 버전 번호 표기 금지**) |
|
||||||
|
| 6 | 사용자 가이드 | `src/AxCopilot/Assets/AX Copilot 사용가이드.htm` | 개발자 가이드에서 버전이력 섹션 제거 후 복사 (**헤더/푸터 버전 표기 없음**) |
|
||||||
|
| 7 | 가이드 암호화 | `src/AxCopilot/Assets/guide_dev.enc`, `guide_user.enc` | 가이드 수정 후 반드시 암호화 재실행 |
|
||||||
|
| 8 | 개발 문서 | `docs/DEVELOPMENT.md` | 버전 이력 추가 |
|
||||||
|
| 9 | 로드맵 문서 | `docs/AGENT_ROADMAP.md/html`, `docs/LAUNCHER_ROADMAP.md/html` | 버전 번호 갱신 |
|
||||||
|
|
||||||
|
### 가이드 문서 관리 워크플로우
|
||||||
|
|
||||||
|
가이드 문서는 **개발자 가이드가 마스터**이며, 사용자 가이드는 이를 기반으로 생성합니다:
|
||||||
|
|
||||||
|
1. **개발자 가이드 수정** (`AX Copilot 개발자가이드.htm`) — 버전 이력 항목 추가. **헤더 `version-tag` div 및 푸터 버전 번호는 표기하지 않음**
|
||||||
|
2. **사용자 가이드 생성** — 개발자 가이드를 복사한 뒤 **버전 이력 섹션 제거** (`<!-- 버전 이력 -->` ~ `</div><!-- /.version-section -->`). 헤더/푸터에 버전 번호 없음
|
||||||
|
3. **암호화 실행** — `encrypt_guides.ps1` 스크립트 실행하여 `.enc` 파일 생성
|
||||||
|
4. **빌드** — `.enc` 파일이 출력 폴더에 복사됨 (평문 .htm은 출력에 포함되지 않음)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 가이드 암호화 명령 (프로젝트 루트에서)
|
||||||
|
powershell -ExecutionPolicy Bypass -File encrypt_guides.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
- 앱에서는 `GuideViewerWindow`가 암호화된 가이드를 복호화하여 내장 뷰어로 표시
|
||||||
|
- 개발자 모드 ON → 개발자 가이드 (버전이력 포함), OFF → 사용자 가이드 (버전이력 없음)
|
||||||
|
- 암호화 키: `GuideEncryptor.cs`에 고정 AES-256-CBC 키 내장 (모든 PC 동일)
|
||||||
|
|
||||||
|
### 사용자 노출 문서 작성 원칙 (사용가이드 · 헬프)
|
||||||
|
|
||||||
|
사용자 가이드와 헬프 화면은 **내부 기술이 노출되지 않도록** 작성합니다:
|
||||||
|
|
||||||
|
| 구분 | 사용 금지 (내부 기술) | 대신 사용 (사용자 관점) |
|
||||||
|
|------|---------------------|----------------------|
|
||||||
|
| 프로토콜 | MCP, JSON-RPC, stdio, P/Invoke, DPAPI | "외부 도구 연결", "암호화 저장" |
|
||||||
|
| 클래스명 | McpClientService, TokenEstimator, DiffService | 기능 설명으로 대체 |
|
||||||
|
| 내부 구조 | FallbackModels, SettingsViewModel, ParentId | "자동 전환", "설정", "분기" |
|
||||||
|
| 코드 패턴 | CJK 가중치, SWE-bench, LCS, TF-IDF | "더 정확한 분석", "검색 개선" |
|
||||||
|
|
||||||
|
**원칙**: 사용자에게는 "무엇을 할 수 있는지"만 전달합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 코드 품질
|
||||||
|
|
||||||
|
### 빌드 기준
|
||||||
|
- 모든 변경 후 `dotnet build` 실행 → **경고 0, 오류 0** 필수
|
||||||
|
- CS8603 (nullable) 경고 즉시 수정
|
||||||
|
|
||||||
|
### 리소스 관리
|
||||||
|
- `IDisposable` 구현 객체는 반드시 해제 (PerformanceCounter, LspClientService 등)
|
||||||
|
- P/Invoke 메모리: `Marshal.AllocHGlobal` 후 `finally`에서 `FreeHGlobal`
|
||||||
|
- WinEvent 훅: `UnhookWinEvent` 보장
|
||||||
|
|
||||||
|
### 에이전트 도구 등록
|
||||||
|
- 새 `IAgentTool` 구현 시 `ToolRegistry.CreateDefault()`에 `Register()` 추가 필수
|
||||||
|
- 도구의 `Parameters` 스키마가 LLM function calling 명세에 정확히 맞는지 확인
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. AI 차단 버전 (클로드 버전) 패턴
|
||||||
|
|
||||||
|
AI 기능이 필요 없는 환경에 배포하거나, AI 기능 문의를 차단해야 할 때 사용하는 패턴입니다.
|
||||||
|
|
||||||
|
### 활성화/비활성화 제어 방법
|
||||||
|
|
||||||
|
`AppSettings.AiEnabled` (기본값 **`false`**) 한 곳만 바꾸면 전체 AI 기능이 제어됩니다.
|
||||||
|
|
||||||
|
| 조건 | 동작 |
|
||||||
|
|------|------|
|
||||||
|
| `AiEnabled = false` | **기본값 (배포 기본)** — AI 전체 차단 |
|
||||||
|
| `AiEnabled = true` | AI 활성화 — 비밀번호 인증 후 설정 가능 |
|
||||||
|
|
||||||
|
### AI 활성화 비밀번호
|
||||||
|
|
||||||
|
- 설정 창 > 일반 탭 > AI 기능 토글 ON 시 비밀번호 다이얼로그 표시
|
||||||
|
- 비밀번호: **`axgo123!`**
|
||||||
|
- 비밀번호 틀리거나 취소 시 토글 자동 복구 (OFF 유지)
|
||||||
|
- 비활성화(OFF)는 비밀번호 없이 즉시 적용
|
||||||
|
- 구현 위치: `SettingsWindow.xaml.cs` `AiEnabled_Changed()`
|
||||||
|
|
||||||
|
### AI 차단 시 적용되는 항목
|
||||||
|
|
||||||
|
| 항목 | 구현 위치 | 설명 |
|
||||||
|
|------|----------|------|
|
||||||
|
| `!` prefix 배지 숨김 | `LauncherViewModel.cs` `ActivePrefix`/`HasActivePrefix` | `!` prefix 인식 안 함 |
|
||||||
|
| `!` 입력 시 결과 없음 | `ChatHandler.cs` `GetItemsAsync` | 빈 리스트 반환 (항목 자체 미표시) |
|
||||||
|
| `!` 실행 차단 | `ChatHandler.cs` `ExecuteAsync` | 실행 불가 |
|
||||||
|
| 트레이 메뉴 항목 숨김 | `App.xaml.cs` `Opening` 이벤트 | "AX Agent 대화하기" 항목 `Collapsed` |
|
||||||
|
| AX Agent 설정 탭 숨김 | `SettingsWindow.xaml.cs` `ApplyAiEnabledState()` | 설정 창의 AX Agent 탭 `Collapsed` |
|
||||||
|
|
||||||
|
### 설정 토글 UI
|
||||||
|
|
||||||
|
- 위치: 설정 창 > 일반 탭 > **AI 기능** 섹션 > "AX Agent (AI 기능) 활성화" 토글
|
||||||
|
- 저장 위치: `%APPDATA%\AxCopilot\settings.dat` → `"ai_enabled": true/false`
|
||||||
|
|
||||||
|
### 신규 AI 기능 추가 시 체크리스트
|
||||||
|
|
||||||
|
AI 관련 기능을 새로 추가하면 `AiEnabled` 체크를 반드시 연동합니다:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 핸들러/도구에서 AI 차단 체크 패턴
|
||||||
|
var settings = (System.Windows.Application.Current as App)?.SettingsService?.Settings;
|
||||||
|
if (settings?.AiEnabled == false) return; // 또는 빈 결과 반환
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 사내/사외 모드 (Network Access Mode)
|
||||||
|
|
||||||
|
### 개요
|
||||||
|
|
||||||
|
배포 환경에 따라 외부 인터넷 접속 허용 여부를 제어합니다.
|
||||||
|
|
||||||
|
| 구분 | 모드 이름 | 기본값 | 설명 |
|
||||||
|
|------|----------|--------|------|
|
||||||
|
| `InternalModeEnabled = true` | **사내 모드** | ✅ 기본 | 외부 인터넷 접속 차단. 사내망 + LLM API만 허용 |
|
||||||
|
| `InternalModeEnabled = false` | **사외 모드** | — | 인터넷 검색, 외부 HTTP 허용 (비밀번호 인증 필요) |
|
||||||
|
|
||||||
|
### 제어 방법
|
||||||
|
|
||||||
|
`AppSettings.InternalModeEnabled` (기본값 **`true`**) 한 곳만 바꾸면 모든 외부 접속 제어가 변경됩니다.
|
||||||
|
|
||||||
|
- 설정 창 > 일반 탭 > **네트워크 모드** 섹션 > "사외 모드 활성화" 토글
|
||||||
|
- 사외 모드 ON 시 비밀번호 다이얼로그 표시 → **`axgo123!`**
|
||||||
|
- 사내 모드 복귀(OFF)는 비밀번호 없이 즉시 적용
|
||||||
|
|
||||||
|
### 모드별 허용/차단 항목
|
||||||
|
|
||||||
|
| 기능 | 사내 모드 | 사외 모드 |
|
||||||
|
|------|---------|---------|
|
||||||
|
| LLM API 호출 (Ollama/Gemini/Claude) | ✅ 허용 | ✅ 허용 |
|
||||||
|
| 사내 MCP 서버 연결 | ✅ 허용 | ✅ 허용 |
|
||||||
|
| 웹 검색 (? 프리픽스) | ❌ 차단 | ✅ 허용 |
|
||||||
|
| `http_request` 도구 외부 URL | ❌ 차단 | ✅ 허용 |
|
||||||
|
| 외부 MCP 서버 연결 | ❌ 차단 | ✅ 허용 (명시적 등록 시) |
|
||||||
|
|
||||||
|
### 코드 체크 패턴
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 외부 접속이 필요한 기능에서 반드시 체크
|
||||||
|
var settings = (System.Windows.Application.Current as App)?.SettingsService?.Settings;
|
||||||
|
if (settings?.InternalModeEnabled == true)
|
||||||
|
return ToolResult.Fail("사내 모드에서는 외부 인터넷 접속이 차단됩니다. 설정에서 사외 모드를 활성화하세요.");
|
||||||
|
|
||||||
|
// URL이 내부 주소인지 검사 (사내 모드에서 허용 가능한 경우)
|
||||||
|
bool IsInternalUrl(string url) =>
|
||||||
|
url.StartsWith("http://localhost", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
url.StartsWith("http://127.", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
url.StartsWith("http://192.168.", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
url.StartsWith("http://10.", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
url.StartsWith("http://172.", StringComparison.OrdinalIgnoreCase);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 신규 외부 접속 기능 추가 시 체크리스트
|
||||||
|
|
||||||
|
외부 인터넷에 접속하는 기능을 추가하면 반드시 `InternalModeEnabled` 체크를 연동합니다:
|
||||||
|
1. 도구 또는 핸들러 실행 초반에 모드 체크
|
||||||
|
2. 사내 모드에서는 명확한 오류 메시지 반환
|
||||||
|
3. SettingsWindow에 해당 기능의 모드 의존성 설명 추가
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 공통 비밀번호 정책
|
||||||
|
|
||||||
|
앱 내 보호된 설정은 모두 동일한 비밀번호를 사용합니다:
|
||||||
|
|
||||||
|
| 보호 항목 | 비밀번호 | 구현 위치 |
|
||||||
|
|----------|---------|---------|
|
||||||
|
| AI 기능 활성화 | `axgo123!` | `SettingsWindow.xaml.cs` `AiEnabled_Changed()` |
|
||||||
|
| 사외 모드 활성화 | `axgo123!` | `SettingsWindow.xaml.cs` `NetworkMode_Changed()` |
|
||||||
|
|
||||||
|
**구현 규칙**:
|
||||||
|
- 비밀번호를 코드에 하드코딩 — 암호화 불필요 (배포 제어용, 보안 목적 아님)
|
||||||
|
- 상수로 분리: `private const string SettingsPassword = "axgo123!";`
|
||||||
|
- 비밀번호 일치 시만 토글 활성화 유지, 불일치/취소 시 토글 자동 복구
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 프로젝트 명칭 체계
|
||||||
|
|
||||||
|
| 구분 | 명칭 | 용도 |
|
||||||
|
|------|------|------|
|
||||||
|
| 앱 전체 | **AX Copilot** | 제품명, 설정, 정보 |
|
||||||
|
| 런처 | **AX Commander** | 명령 입력창 |
|
||||||
|
| AI 대화 | **AX Agent** | Chat/Cowork/Code 대화 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 사내 환경 개발 원칙
|
||||||
|
|
||||||
|
### 외부 의존 최소화 (항상 적용)
|
||||||
|
- **데이터 로컬 저장** — 설정, 대화, 클립보드, 인덱스, 로그 등 모든 데이터는 `%APPDATA%\AxCopilot\` 로컬에 저장. 클라우드 동기화 없음
|
||||||
|
- **플러그인 설치** — URL 기반 다운로드 금지. 로컬 zip 파일 기반 설치만 허용
|
||||||
|
- **코드 검색/인덱싱** — 외부 임베딩 API 사용 금지. 로컬 TF-IDF 또는 로컬 임베딩 엔진(ONNX) 사용
|
||||||
|
- **업데이트 확인** — 외부 서버 자동 업데이트 체크 금지. 인스톨러를 통한 수동 업그레이드만 지원
|
||||||
|
- **텔레메트리** — 사용 통계를 외부로 전송하지 않음. 모든 통계는 로컬 파일에만 기록
|
||||||
|
|
||||||
|
### 항상 허용되는 외부 접속
|
||||||
|
- LLM API 호출 (Ollama/vLLM은 사내 서버, Gemini/Claude는 설정에 따라)
|
||||||
|
- 사내 MCP 서버 연결 (설정에서 명시적 등록된 것만)
|
||||||
|
|
||||||
|
### 사외 모드에서만 허용 (섹션 6 참조)
|
||||||
|
- 인터넷 웹 검색 (? 프리픽스)
|
||||||
|
- `http_request` 도구의 외부 URL 호출
|
||||||
|
- 외부 MCP 서버 연결
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 문서 관리 원칙
|
||||||
|
|
||||||
|
### 기본 원칙: .md 파일이 마스터
|
||||||
|
- **모든 로드맵·계획 문서는 `.md` 파일로 관리**합니다. 기본 작업(기능 개발·계획 수립·완료 기록)은 항상 `.md` 파일만 업데이트합니다.
|
||||||
|
- **HTML 웹 문서는 명시적으로 요청할 때만 업데이트**합니다. ("웹 문서도 업데이트해줘" 또는 "HTML 문서 갱신해줘" 요청 시에만 작업)
|
||||||
|
- HTML 문서는 `.md` 마스터를 기반으로 생성되는 **파생 문서**입니다. 자동으로 동기화하지 않습니다.
|
||||||
|
|
||||||
|
### 문서 체계
|
||||||
|
|
||||||
|
| 문서 (.md 마스터) | HTML (파생) | 관리 대상 | .md 업데이트 시점 |
|
||||||
|
|-----------------|------------|----------|-----------------|
|
||||||
|
| `docs/AGENT_ROADMAP.md` | `docs/AGENT_ROADMAP.html` | **대화 서비스** Phase별 기능, 완료 이력, 기술부채 | Phase 완료 시, 기능 추가 시 |
|
||||||
|
| `docs/LAUNCHER_ROADMAP.md` | `docs/LAUNCHER_ROADMAP.html` | **런처** Phase별 기능, 완료 이력, 경쟁 비교 | Phase 완료 시, 기능 추가 시 |
|
||||||
|
| `docs/NEXT_ROADMAP.md` | `docs/NEXT_ROADMAP.html` | **종합** 경쟁 분석, 기술 동향, 차기 계획 | 분기별 또는 대규모 계획 변경 시 |
|
||||||
|
| `docs/DEVELOPMENT.md` | — | **개발 상세** 아키텍처, 핸들러, 버전 이력, 코드 패턴 | 매 버전 배포 시 |
|
||||||
|
|
||||||
|
### 문서 업데이트 규칙
|
||||||
|
- **기능 개발 완료 시**: 해당 영역 .md 로드맵(AGENT/LAUNCHER)에 완료 표시 + 구현 내용 기록
|
||||||
|
- **배포 시**: DEVELOPMENT.md 버전 이력 추가, 사용자 가이드/헬프 갱신
|
||||||
|
- **차기 계획 수립 시**: NEXT_ROADMAP.md 업데이트 (경쟁 분석 반영)
|
||||||
|
- **HTML 동기화 요청 시에만**: 해당 .md 내용을 기반으로 HTML 파일 갱신 (열고/닫기 토글, badge 스타일 done/plan/hold 통일)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 고도화 계획 수립 원칙
|
||||||
|
|
||||||
|
### 외부 동향 기반 계획 수립
|
||||||
|
고도화 계획(Phase)을 수립할 때는 **내부 개발 필요성만이 아닌 외부 동향**을 종합적으로 반영합니다:
|
||||||
|
|
||||||
|
| 관점 | 검토 사항 |
|
||||||
|
|------|----------|
|
||||||
|
| **경쟁 서비스** | Claude Code, Cursor, Windsurf, GitHub Copilot, Raycast 등 최신 기능/UX 비교 |
|
||||||
|
| **최신 논문/기술** | Agentic Coding Survey, SWE-Agent, CodeAct, Reflexion 등 에이전트 코딩 연구 동향 |
|
||||||
|
| **업계 표준** | MCP 프로토콜, SKILL.md 오픈 포맷, LSP, DAP 등 표준 프로토콜 채택 여부 |
|
||||||
|
| **사내 환경** | 네트워크 제한, 보안 정책, Python/Node 설치 현황, 사용 빈도가 높은 워크플로우 |
|
||||||
|
| **커뮤니티 스킬** | Anthropic 공식 스킬, 오픈소스 프롬프트 엔지니어링 기법, 검증된 에이전트 패턴 |
|
||||||
|
|
||||||
|
### 앱 크기 관리
|
||||||
|
배포 앱(인스톨러)의 크기가 과도하게 커지지 않도록 관리합니다:
|
||||||
|
|
||||||
|
- **기본 배포 크기 목표**: 인스톨러 **150MB 이하** 유지 (현재 ~80MB)
|
||||||
|
- **대형 의존성 추가 시**: ONNX 모델, 임베딩 엔진, 사전 데이터 등은 **별도 선택적 다운로드** 또는 **로컬 zip 설치** 방식 검토
|
||||||
|
- **스킬 파일**: 내장 스킬(`.skill.md`)은 텍스트 기반이므로 크기 부담 없음 (수십 KB 단위). 적극 번들 가능
|
||||||
|
- **NuGet 패키지**: 새 패키지 추가 시 DLL 크기 확인. 단일 기능에 10MB+ 패키지는 대안 검토
|
||||||
|
- **런타임 의존**: Python/Node 스크립트 기반 기능은 사용자 PC 런타임에 의존 → 앱 크기 증가 없음
|
||||||
|
- **리소스 파일**: 이미지/아이콘은 SVG 또는 시스템 폰트(Segoe MDL2 Assets) 우선. 대형 비트맵 금지
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 코드 설계 원칙 (SOLID + 디자인 패턴)
|
||||||
|
|
||||||
|
### SOLID 원칙 준수 (필수)
|
||||||
|
|
||||||
|
#### S — 단일 책임 원칙 (SRP)
|
||||||
|
- **클래스 하나 = 책임 하나**. 에이전트 도구 클래스는 도구 로직만, UI 코드비하인드는 UI만 담당
|
||||||
|
- 500줄 이상 클래스는 분리 검토. 메서드는 20줄 이하 권장
|
||||||
|
- 파일 I/O, 비즈니스 로직, UI 렌더링이 같은 클래스에 섞이는 것 금지
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 금지: AgentLoopService가 UI도 업데이트
|
||||||
|
// 허용: AgentLoopService → 이벤트 발행 → ViewModel이 UI 갱신
|
||||||
|
```
|
||||||
|
|
||||||
|
#### O — 개방/폐쇄 원칙 (OCP)
|
||||||
|
- 새 도구 추가 시 기존 `AgentLoopService` 수정 없이 `IAgentTool` 구현 + Registry 등록만으로 확장
|
||||||
|
- 새 훅 이벤트 추가 시 기존 훅 처리기 수정 없이 새 핸들러 등록으로 확장
|
||||||
|
- `switch/if-else` 체인으로 타입 분기하는 것 지양 → 다형성 또는 전략 패턴으로 대체
|
||||||
|
|
||||||
|
#### L — 리스코프 치환 원칙 (LSP)
|
||||||
|
- `IAgentTool` 구현체는 항상 교환 가능해야 함 — 특정 구현에만 의존하는 코드 금지
|
||||||
|
- `ToolResult.Ok()` / `ToolResult.Error()` 반환 규약은 모든 도구 구현체에서 일관 유지
|
||||||
|
|
||||||
|
#### I — 인터페이스 분리 원칙 (ISP)
|
||||||
|
- 거대 인터페이스 금지. `IAgentTool`은 `Execute`, `Parameters`, `Name`만 정의
|
||||||
|
- 추가 기능(검증, 로깅, 캐시)은 별도 인터페이스(`IVerifiable`, `IAuditable`)로 분리
|
||||||
|
- 구현체가 사용하지 않는 메서드를 강제하는 인터페이스 금지
|
||||||
|
|
||||||
|
#### D — 의존성 역전 원칙 (DIP)
|
||||||
|
- 구체 클래스가 아닌 **인터페이스/추상 클래스에 의존**
|
||||||
|
- `AgentLoopService`는 `IAgentTool[]`, `ILlmService`, `IHookRunner`에만 의존 (구체 구현 직접 참조 금지)
|
||||||
|
- 의존성 주입: 생성자 주입 우선. `App.SettingsService`처럼 전역 싱글턴 직접 접근은 서비스 계층에만 허용
|
||||||
|
|
||||||
|
### 적극 사용할 디자인 패턴
|
||||||
|
|
||||||
|
#### Strategy 패턴 — 에이전트 도구, 훅 타입, 권한 모드
|
||||||
|
```csharp
|
||||||
|
// 훅 타입별 전략 분리
|
||||||
|
public interface IHookExecutor { Task<HookResult> ExecuteAsync(HookContext ctx); }
|
||||||
|
public class CommandHookExecutor : IHookExecutor { ... }
|
||||||
|
public class PromptHookExecutor : IHookExecutor { ... } // NEW: LLM 검사
|
||||||
|
public class AgentHookExecutor : IHookExecutor { ... } // NEW: 에이전트 루프
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Observer 패턴 — 에이전트 이벤트, 훅 이벤트
|
||||||
|
```csharp
|
||||||
|
// AgentLoopService에서 이벤트 발행 → 다수 구독자 (UI, 훅, 감사 로그)
|
||||||
|
public event EventHandler<AgentEvent> AgentEventOccurred;
|
||||||
|
// 구독: WorkflowAnalyzer, HookRunner, AuditLogService 각각 독립 구독
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Factory 패턴 — 도구 생성, 훅 생성, 에이전트 생성
|
||||||
|
```csharp
|
||||||
|
// 도구 팩토리: 타입 기반 생성, 외부에서 new 금지
|
||||||
|
public static class AgentToolFactory
|
||||||
|
{
|
||||||
|
public static IAgentTool Create(string toolName, LlmSettings settings) { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Decorator 패턴 — 도구 검증·로깅·위험도 래핑
|
||||||
|
```csharp
|
||||||
|
// 기존 도구에 검증/로깅 기능 추가 — 도구 자체 수정 없이
|
||||||
|
public class VerifiedToolDecorator : IAgentTool
|
||||||
|
{
|
||||||
|
private readonly IAgentTool _inner;
|
||||||
|
public VerifiedToolDecorator(IAgentTool inner) { _inner = inner; }
|
||||||
|
public async Task<ToolResult> ExecuteAsync(...)
|
||||||
|
{
|
||||||
|
var result = await _inner.ExecuteAsync(...);
|
||||||
|
await RunPostVerificationAsync(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Chain of Responsibility — 훅 체인, 권한 규칙 체인
|
||||||
|
```csharp
|
||||||
|
// 권한 규칙을 체인으로 처리: Allow규칙 → Deny규칙 → 모드 기본값
|
||||||
|
public abstract class PermissionRule
|
||||||
|
{
|
||||||
|
protected PermissionRule? _next;
|
||||||
|
public abstract PermissionDecision Evaluate(ToolCall call);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Repository 패턴 — 설정, 대화 이력, 에이전트 메모리
|
||||||
|
```csharp
|
||||||
|
public interface IAgentMemoryRepository
|
||||||
|
{
|
||||||
|
Task<AgentMemory?> GetAsync(string agentType, string projectId);
|
||||||
|
Task SaveAsync(AgentMemory memory);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Command 패턴 — 슬래시 명령, 커맨드 팔레트
|
||||||
|
```csharp
|
||||||
|
public interface ISlashCommand
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
string Description { get; }
|
||||||
|
Task ExecuteAsync(string arguments, IChatContext context);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 구조 분리 원칙
|
||||||
|
|
||||||
|
#### 계층 분리 규칙
|
||||||
|
```
|
||||||
|
UI 계층 (Views/ViewModels)
|
||||||
|
↓ 이벤트/명령 (Commands, Events)
|
||||||
|
서비스 계층 (Services)
|
||||||
|
↓ 인터페이스 (IAgentTool, IHookExecutor 등)
|
||||||
|
도메인 계층 (Models, Tools)
|
||||||
|
↓ 데이터 접근 (Repositories)
|
||||||
|
인프라 계층 (외부 API, 파일 시스템)
|
||||||
|
```
|
||||||
|
- **계층 역방향 의존 금지**: 도메인 계층이 UI를 참조하는 것 금지
|
||||||
|
- **서비스 계층 간 직접 호출 지양**: 이벤트/메시지 버스로 느슨한 결합
|
||||||
|
|
||||||
|
#### 에이전트 도구 분리 원칙
|
||||||
|
- 도구 클래스는 `Services/AgentTools/` 하위의 **카테고리별 폴더**에 배치
|
||||||
|
- 각 도구는 `독립 파일` 1개 — 여러 도구를 하나의 파일에 합치는 것 금지
|
||||||
|
- 도구 간 직접 호출 금지 — 공통 로직은 `Services/AgentToolHelpers/`에 분리
|
||||||
|
|
||||||
|
#### 설정 분리 원칙 (기존 원칙 강화)
|
||||||
|
- Cowork/Code 전용 설정은 반드시 분리 (공통 설정에 넣지 않음)
|
||||||
|
- 새 기능 추가 시 설정 클래스 → ViewModel → UI → 코드 순서로 구현
|
||||||
|
|
||||||
|
### 새 기능 구현 체크리스트
|
||||||
|
|
||||||
|
새 Phase 기능을 구현하기 전 확인:
|
||||||
|
1. **인터페이스 먼저**: 구체 구현 전 `IXxx` 인터페이스 정의
|
||||||
|
2. **단일 책임**: 클래스가 2가지 이상의 이유로 변경될 수 있으면 분리
|
||||||
|
3. **패턴 적합성**: Strategy/Observer/Decorator 중 적합한 패턴 선택
|
||||||
|
4. **의존성 방향**: 새 클래스의 의존성이 올바른 방향인지 확인
|
||||||
|
5. **설정 연동**: 설정 없이 하드코딩된 동작 금지
|
||||||
|
6. **테스트 가능성**: 외부 의존(파일, API)을 인터페이스로 추상화하여 단위 테스트 가능하게
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. AX Agent 채팅 화면 UI/UX 원칙 (Claude.ai + Codex 스타일)
|
||||||
|
|
||||||
|
### 핵심 패러다임: AX Agent = 독립 앱 공간
|
||||||
|
|
||||||
|
**절대 원칙**: AX Agent와 관련된 **모든** 설정은 ChatWindow 내부에서 처리한다.
|
||||||
|
- SettingsWindow에서 **AX Agent 탭을 완전 제거**. AX Agent 관련 설정은 ChatWindow 내 설정 패널로 이관.
|
||||||
|
- 사용자는 ChatWindow를 벗어나지 않고 모델 변경, 도구 토글, 권한 모드, 에이전트 파라미터, API 키까지 모두 설정 가능해야 함.
|
||||||
|
- SettingsWindow에는 앱 전역 설정(테마, 핫키, 런처, 인덱싱)만 남긴다.
|
||||||
|
|
||||||
|
> **레퍼런스**: Claude.ai — 대화 목록 + 채팅 + 설정이 단일 창 내 패널로 구성. Codex — 에이전트 제어 항목(모델, 도구, 권한, Plan) 전부 채팅 헤더/사이드바에 인라인 배치. 별도 설정 다이얼로그 없음.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 전체 레이아웃 구조 (3-Pane)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ [좌측 사이드바 260px] │ [메인 채팅 영역 — 가변] │ [우측 패널 300px] │
|
||||||
|
│ │ │ (토글, 기본 접힘) │
|
||||||
|
│ ┌──────────────────┐ │ ┌─────────────────────┐ │ │
|
||||||
|
│ │ ≡ AX Agent ✕ │ │ │ 현재 탭 이름 │ │ ┌───────────────┐ │
|
||||||
|
│ └──────────────────┘ │ │ 모델▾ Plan▾ 권한▾ │ │ │ ⚙ 설정 패널 │ │
|
||||||
|
│ │ └─────────────────────┘ │ │ ───────────── │ │
|
||||||
|
│ [ Chat │ Cowork│Code] │ │ │ 탭별 에이전트 │ │
|
||||||
|
│ ──────────────────── │ [메시지 스트림] │ │ 파라미터 │ │
|
||||||
|
│ ▸ 프리셋1 │ │ │ 모델/API 설정 │ │
|
||||||
|
│ ▸ 프리셋2 │ │ │ 도구 토글 │ │
|
||||||
|
│ ▸ 프리셋3 │ │ │ MCP 서버 │ │
|
||||||
|
│ ──────────────────── │ │ └───────────────┘ │
|
||||||
|
│ [+ 새 대화] │ │ │
|
||||||
|
│ ──────────────────── │ ┌──────────────────────┐ │ ┌───────────────┐ │
|
||||||
|
│ 오늘 │ │ @멘션 /스킬 📎 ⚙ │ │ │ 🔀 워크플로우 │ │
|
||||||
|
│ · 대화 제목 1 │ │ [ 입력 텍스트 ] │ │ └───────────────┘ │
|
||||||
|
│ · 대화 제목 2 │ │ 모델칩 권한칩 [전송]│ │ ┌───────────────┐ │
|
||||||
|
│ 어제 │ └──────────────────────┘ │ │ 📄 Diff 뷰 │ │
|
||||||
|
│ · 대화 제목 3 │ │ └───────────────┘ │
|
||||||
|
└──────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 좌측 사이드바 (AgentSidebarView) — Claude.ai 스타일
|
||||||
|
|
||||||
|
#### 구조 및 동작
|
||||||
|
- **헤더**: `≡ AX Agent` 로고 + 사이드바 접기 버튼 (최소 48px 아이콘 모드로 접힘)
|
||||||
|
- **탭 세그먼트**: `Chat | Cowork | Code` — 가로 3분할 세그먼트 컨트롤 (Border + MouseLeftButtonUp, 선택 탭 AccentColor 배경)
|
||||||
|
- **프리셋 목록**: 현재 탭의 프리셋 항목 직접 목록 표시. 클릭 시 즉시 적용. 우클릭 커스텀 Popup (편집/삭제)
|
||||||
|
- **새 대화 버튼**: `[+ 새 대화]` — 전체 너비 Border 버튼, 호버 시 AccentColor 틴트
|
||||||
|
- **대화 이력**: 날짜 그룹(`오늘 / 어제 / 이전 7일 / 이전 30일`) 구분선 + 대화명. 클릭 시 해당 세션 복원. 우클릭 커스텀 Popup (이름변경/삭제/즐겨찾기)
|
||||||
|
- **하단**: ⚙ 설정 아이콘 → 우측 설정 패널 토글 (Claude.ai 프로필 메뉴 대응)
|
||||||
|
|
||||||
|
#### 크기/테마
|
||||||
|
- 기본 너비 260px, 접기 시 48px (아이콘만)
|
||||||
|
- 배경: `LauncherBackground`, 구분선: `BorderColor` 1px, 선택 항목: `ItemHoverBackground`
|
||||||
|
- 접기/펼치기: Width 애니메이션 260→48px, 180ms EaseInOut
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 메인 채팅 영역 — 탭별 콘텐츠
|
||||||
|
|
||||||
|
#### 세션 헤더 바 (탭당 고정)
|
||||||
|
|
||||||
|
탭 전환 시 해당 탭의 헤더로 교체됨. 항상 표시.
|
||||||
|
|
||||||
|
| 위치 | 컨트롤 | 구현 | 설명 |
|
||||||
|
|------|--------|------|------|
|
||||||
|
| 좌측 | 현재 탭 레이블 | TextBlock | "Chat", "Cowork", "Code" |
|
||||||
|
| 중앙 | 모델 선택칩 | Border + Popup | 현재 모델명 + ▾. 클릭 시 등록 모델 목록 팝업 |
|
||||||
|
| 중앙 | Plan 모드 칩 | Border 3-state | Off → Auto → Always 순환 클릭. 활성=AccentColor |
|
||||||
|
| 중앙 | 권한 모드 칩 | Border + Popup | Default / AcceptEdits / Plan / Bypass |
|
||||||
|
| 우측 | 도구 아이콘 열 | 아이콘 N개 | 활성=기능색, 비활성=SecondaryText 흐림. 클릭 토글 |
|
||||||
|
| 우측 | ⚙ 설정 버튼 | Border | 우측 설정 패널 슬라이드인 토글 |
|
||||||
|
| 우측 | 🔀 워크플로우 | Border | 워크플로우 분석기 우측 패널 열기 |
|
||||||
|
|
||||||
|
#### 메시지 스트림
|
||||||
|
|
||||||
|
- 사용자 메시지: 우측 정렬, `ItemBackground` 배경 버블, 최대 너비 70%
|
||||||
|
- AI 메시지: 좌측 정렬, 배경 없음 (Claude.ai 스타일), 마크다운 렌더링
|
||||||
|
- 도구 호출 블록: 접히는 `Border` (`▶ file_write` → 클릭 시 펼쳐서 파라미터/결과 표시)
|
||||||
|
- 스트리밍 중: 커서 깜빡임 애니메이션 (Opacity 0→1, 500ms 반복)
|
||||||
|
- 신규 메시지 SlideIn: TranslateTransform Y +20→0, Opacity 0→1, 120ms EaseOut
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 우측 설정 패널 (AgentSettingsPanel) — 필수 구현
|
||||||
|
|
||||||
|
**⚙ 클릭 시 우측에서 슬라이드인 (TranslateTransform X +300→0, 200ms EaseOut)**
|
||||||
|
**기존 SettingsWindow의 AX Agent 탭을 이 패널로 완전 대체.**
|
||||||
|
|
||||||
|
#### 패널 구성 (탭별 섹션 분기)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────── ⚙ 설정 ────── [✕] ┐
|
||||||
|
│ ── 현재 탭: Chat / Cowork / Code ── │
|
||||||
|
│ │
|
||||||
|
│ [모델 & 서비스] │
|
||||||
|
│ LLM 서비스 [Ollama ▾] │
|
||||||
|
│ 모델 [llama3:8b ▾] │
|
||||||
|
│ API 엔드포인트 [____________] │
|
||||||
|
│ API 키 [•••••••• 👁] │
|
||||||
|
│ │
|
||||||
|
│ [에이전트 동작] │
|
||||||
|
│ 최대 반복 횟수 [──────○──] 20 │
|
||||||
|
│ 오류 시 재시도 [──○──────] 3 │
|
||||||
|
│ 병렬 도구 실행 ◉──── (토글) │
|
||||||
|
│ │
|
||||||
|
│ [탭 전용 설정] ← 탭에 따라 다름 │
|
||||||
|
│ (Cowork) 검증 강제 ◉──── │
|
||||||
|
│ (Code) LSP 분석 ◉──── │
|
||||||
|
│ (Code) 작업 폴더 [경로... 📁] │
|
||||||
|
│ │
|
||||||
|
│ [도구 관리] │
|
||||||
|
│ file_write ◉──── 활성 │
|
||||||
|
│ file_read ◉──── 활성 │
|
||||||
|
│ git_tool ────◉ 비활성 │
|
||||||
|
│ … │
|
||||||
|
│ │
|
||||||
|
│ [MCP 서버] │
|
||||||
|
│ ● server1 연결됨 [비활성화] │
|
||||||
|
│ ○ server2 오프라인 [재연결] │
|
||||||
|
│ │
|
||||||
|
│ [프리셋] │
|
||||||
|
│ 현재 설정으로 저장 [저장] │
|
||||||
|
│ 프리셋 관리 [관리 →] │
|
||||||
|
│ │
|
||||||
|
│ [고급] │
|
||||||
|
│ 폴백 모델 목록 [편집] │
|
||||||
|
│ 프로젝트 규칙 ◉──── 활성 │
|
||||||
|
│ AX.md 편집 [열기 →] │
|
||||||
|
└───────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 설정 패널 구현 규칙
|
||||||
|
- 모든 컨트롤: ToggleSwitch 또는 Border+Popup 드롭다운 (Section 1 원칙 준수)
|
||||||
|
- API 키 필드: `PasswordBox` 스타일 + 👁 토글로 표시/숨김
|
||||||
|
- 탭별 분기: `ActiveTab == "Code"` 조건으로 탭 전용 섹션 표시/숨김
|
||||||
|
- 설정 변경 즉시 저장 (`SettingsService.Save()`) — 별도 저장 버튼 불필요
|
||||||
|
- 슬라이더: WPF `Slider` + 현재값 TextBlock 우측 표시
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### SettingsWindow 잔류 원칙 (AX Agent 탭 제거)
|
||||||
|
|
||||||
|
SettingsWindow에 **남기는 항목** (앱 전역 설정만):
|
||||||
|
- **일반**: AI 활성화(비밀번호), 네트워크 모드(비밀번호), 앱 시작 설정, 개발자 모드
|
||||||
|
- **런처**: 인덱싱 경로/확장자, 핫키, 독 바, 테마 선택
|
||||||
|
- **플러그인**: 플러그인 설치/제거 (PluginGalleryViewModel)
|
||||||
|
- **퀵링크**: QuickLinkEntry 목록 관리
|
||||||
|
- **AI 스니펫**: AiSnippetTemplate 목록 관리
|
||||||
|
- **감사 로그**: 로그 파일 열기, 보존 기간 설정
|
||||||
|
|
||||||
|
SettingsWindow에서 **제거 (ChatWindow 이관 완료)**:
|
||||||
|
- AX Agent 탭 전체 → ChatWindow 우측 설정 패널
|
||||||
|
- 모델/LLM 서비스 설정 → 설정 패널 [모델 & 서비스] 섹션
|
||||||
|
- 에이전트 파라미터(반복, 재시도, 병렬) → 설정 패널 [에이전트 동작] 섹션
|
||||||
|
- 도구 개별 토글 → 설정 패널 [도구 관리] 섹션 + 헤더 바 아이콘
|
||||||
|
- MCP 서버 활성화 → 설정 패널 [MCP 서버] 섹션 (등록/삭제는 SettingsWindow)
|
||||||
|
- 프리셋 관리 → 설정 패널 [프리셋] 섹션
|
||||||
|
- 프로젝트 규칙, 작업 폴더 → 설정 패널 [고급] 섹션
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 입력 영역 (AgentInputArea) — Claude.ai + Codex 스타일
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────┐
|
||||||
|
│ @멘션 /스킬 📎 첨부 │
|
||||||
|
│ ┌──────────────────────────────────────────────────┐ │
|
||||||
|
│ │ 메시지를 입력하세요… │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ └──────────────────────────────────────────────────┘ │
|
||||||
|
│ [모델명 칩] [권한 칩] [Plan 칩] ⚙설정 [▶전송] │
|
||||||
|
└──────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- **상단 툴바**: `@` (파일 멘션 자동완성) · `/` (스킬/슬래시 명령) · 📎 (파일/이미지 첨부)
|
||||||
|
- **텍스트 입력**: 최소 60px, 최대 220px 자동 확장, Ctrl+Enter 전송
|
||||||
|
- **하단 칩 열**: 현재 모델명 칩 (클릭 시 변경) + 권한 모드 칩 + Plan 칩 — 항상 현재 상태 표시
|
||||||
|
- **⚙ 버튼**: 우측 설정 패널 토글 (헤더 바와 동일 동작)
|
||||||
|
- **전송 버튼 [▶]**: 실행 중 → `[■ 중단]`으로 전환, Border + MouseLeftButtonUp 패턴
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 구현 클래스 구조
|
||||||
|
|
||||||
|
```
|
||||||
|
Views/
|
||||||
|
ChatWindow.xaml # 최상위 창 — 3-pane Grid 구조
|
||||||
|
ChatWindow.xaml.cs # 탭 전환, 패널 토글, 입력 처리
|
||||||
|
|
||||||
|
Controls/ # 재사용 UserControl
|
||||||
|
AgentSidebarView.xaml # 탭 세그먼트 + 프리셋 + 대화 이력
|
||||||
|
AgentSidebarView.xaml.cs
|
||||||
|
AgentSessionHeaderBar.xaml # 모델/Plan/권한/도구 칩 바
|
||||||
|
AgentSessionHeaderBar.xaml.cs
|
||||||
|
AgentSettingsPanel.xaml # 우측 슬라이드인 설정 패널 (전체 AX Agent 설정)
|
||||||
|
AgentSettingsPanel.xaml.cs
|
||||||
|
AgentInputArea.xaml # 멀티기능 입력 영역
|
||||||
|
AgentInputArea.xaml.cs
|
||||||
|
AgentDiffPanel.xaml # 우측 Diff 뷰 패널
|
||||||
|
AgentDiffPanel.xaml.cs
|
||||||
|
|
||||||
|
ViewModels/
|
||||||
|
ChatWindowViewModel.cs # 창 통합 VM (탭, 패널 상태)
|
||||||
|
AgentSidebarViewModel.cs # 사이드바 VM (탭/프리셋/이력)
|
||||||
|
AgentSessionHeaderViewModel.cs # 헤더 칩 VM
|
||||||
|
AgentSettingsPanelViewModel.cs # 설정 패널 VM (모든 AX Agent 설정)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 파일 배치 원칙
|
||||||
|
- 기존 `ChatWindow.xaml` / `ChatWindow.xaml.cs` 를 리팩터링. 새 파일을 신규 생성.
|
||||||
|
- `AgentSettingsPanel`은 독립 UserControl — `ChatWindow`에 `Grid.Column="2"`로 배치.
|
||||||
|
- 우측 패널 3종 (설정/워크플로우/Diff)은 `Visibility` + `TranslateTransform`으로 전환.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 애니메이션 / 전환 원칙
|
||||||
|
|
||||||
|
| 동작 | 구현 | 시간 |
|
||||||
|
|------|------|------|
|
||||||
|
| 사이드바 접기/펼치기 | Width 260→48px DoubleAnimation EaseInOut | 180ms |
|
||||||
|
| 우측 패널 슬라이드인 | TranslateTransform X +300→0 EaseOut | 200ms |
|
||||||
|
| 우측 패널 슬라이드아웃 | TranslateTransform X 0→+300 EaseIn | 150ms |
|
||||||
|
| 탭 전환 | Opacity 0→1 + TranslateY +8→0 | 120ms |
|
||||||
|
| 메시지 신규 등장 | Opacity 0→1 + TranslateY +16→0 EaseOut | 120ms |
|
||||||
|
| 스트리밍 커서 | Opacity 0↔1 RepeatForever | 500ms |
|
||||||
|
| 도구 블록 펼치기 | Height Auto DoubleAnimation | 150ms |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. 관련 문서
|
||||||
|
|
||||||
|
| 문서 | 경로 | 설명 |
|
||||||
|
|------|------|------|
|
||||||
|
| 개발 문서 | `docs/DEVELOPMENT.md` | 아키텍처, 핸들러, 버전 이력, 개발 원칙 상세 |
|
||||||
|
| AX Agent 로드맵 | `docs/AGENT_ROADMAP.md` | 대화 서비스 고도화 계획 (Phase별) — HTML은 요청 시만 갱신 |
|
||||||
|
| 런처 로드맵 | `docs/LAUNCHER_ROADMAP.md` | 런처 고도화 계획 (Phase별) — HTML은 요청 시만 갱신 |
|
||||||
|
| 차기 종합 계획 | `docs/NEXT_ROADMAP.md` | v1.7.1~v2.0 CC 내부 문서 기반 전면 개정판 — HTML은 요청 시만 갱신 |
|
||||||
|
| Claude Code 참고 문서 | `docs/claude-code-docs-main/` | CC 훅·스킬·멀티에이전트·권한·메모리·SDK 내부 아키텍처 문서 |
|
||||||
|
| 사용자 가이드 | `src/AxCopilot/Assets/AX Copilot 사용가이드.htm` | 단축키/예약어 가이드 |
|
||||||
|
| 브랜딩 가이드 | `src/AxCopilot/Assets/BRANDING_가이드.md` | 아이콘/색상/명칭 규칙 |
|
||||||
221
README.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
# AX Commander
|
||||||
|
|
||||||
|
Windows 전용 시맨틱 런처 & 워크스페이스 매니저
|
||||||
|
|
||||||
|
> Alfred (macOS)에서 영감을 받아 Windows 환경에 최적화된 키보드 중심 생산성 도구입니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 주요 기능 (프리픽스 치트시트)
|
||||||
|
|
||||||
|
| 프리픽스 | 기능 | 예시 |
|
||||||
|
|----------|------|------|
|
||||||
|
| *(없음)* | 앱·파일 퍼지 검색 + 앱 단축키 | `vscode`, `크롬`, `ㅅㄷ` (초성) |
|
||||||
|
| `=` | **계산기** — 수식 즉시 계산, Enter로 결과 복사 | `= sqrt(16)`, `= 2^10`, `= sin(30)` |
|
||||||
|
| `/` | **시스템 명령** — 잠금·절전·재시작·종료 | `/lock`, `/sleep`, `/shutdown` |
|
||||||
|
| `;` | **텍스트 스니펫** — 키워드로 저장된 텍스트 붙여넣기 | `;addr`, `;sig` |
|
||||||
|
| `#` | **클립보드 히스토리** — 복사 이력 검색 & 재사용 | `# hello`, `#` |
|
||||||
|
| `@` | URL 단축키 | `@gh` → GitHub 열기 |
|
||||||
|
| `~` | 폴더 단축키 | `~dl` → Downloads 폴더 |
|
||||||
|
| `>` | 명령 실행 / 배치 단축키 | `>git status` |
|
||||||
|
| `$` | 클립보드 텍스트 변환 (12종) | `$json`, `$b64e`, `$upper`, `$ts` |
|
||||||
|
| `!` | 워크스페이스 저장·복원 | `!save work`, `!restore work` |
|
||||||
|
|
||||||
|
### Alfred 대비 기능 현황
|
||||||
|
|
||||||
|
| 기능 | Alfred | AX Commander |
|
||||||
|
|------|--------|-----------------|
|
||||||
|
| 앱 퍼지 검색 | ✅ | ✅ |
|
||||||
|
| 한국어 초성 검색 | ❌ | ✅ |
|
||||||
|
| 파일 검색 | ✅ | ✅ (exe/lnk/bat/ps1) |
|
||||||
|
| 계산기 | ✅ | ✅ `=` 프리픽스 |
|
||||||
|
| 시스템 명령 | ✅ | ✅ `/` 프리픽스 (7가지) |
|
||||||
|
| 텍스트 스니펫 | ✅ | ✅ `;` 프리픽스 + 변수 치환 |
|
||||||
|
| 클립보드 히스토리 | ✅ | ✅ `#` 프리픽스 |
|
||||||
|
| 클립보드 변환 | ❌ | ✅ `$` 프리픽스 (12종) |
|
||||||
|
| URL 단축키 | ✅ | ✅ `@` 프리픽스 |
|
||||||
|
| 폴더 단축키 | ✅ | ✅ `~` 프리픽스 |
|
||||||
|
| 터미널 명령 | ✅ | ✅ `>` 프리픽스 |
|
||||||
|
| 워크스페이스 관리 | ❌ | ✅ `!` 프리픽스 |
|
||||||
|
| 플러그인 SDK | ✅ | ✅ (`IActionHandler`) |
|
||||||
|
| HTTP API 스킬 | ✅ | ✅ (`.skill.json`) |
|
||||||
|
| 테마 커스터마이징 | ❌ | ✅ (7종 프리셋 + 완전 커스텀) |
|
||||||
|
| 설정 UI | ✅ | ✅ (7탭 전체 GUI 설정) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 설치 및 빌드
|
||||||
|
|
||||||
|
### 요구 사항
|
||||||
|
|
||||||
|
- **OS**: Windows 10 20H2 이상 (Windows 11 권장)
|
||||||
|
- **.NET**: 8.0 Runtime (Self-contained 빌드 시 불필요)
|
||||||
|
|
||||||
|
### 빌드
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 소스 클론
|
||||||
|
git clone https://github.com/your/oledic.git
|
||||||
|
cd "oledic/AX Commander"
|
||||||
|
|
||||||
|
# 개발 실행
|
||||||
|
dotnet run --project src/AxCommander
|
||||||
|
|
||||||
|
# Release 단일 파일 빌드 (self-contained)
|
||||||
|
dotnet publish src/AxCommander -c Release -r win-x64 --self-contained
|
||||||
|
```
|
||||||
|
|
||||||
|
### 데이터 경로
|
||||||
|
|
||||||
|
| 용도 | 경로 |
|
||||||
|
|------|------|
|
||||||
|
| 설정 파일 | `%APPDATA%\AxCommander\settings.json` |
|
||||||
|
| 로그 | `%APPDATA%\AxCommander\logs\app-YYYY-MM-DD.log` |
|
||||||
|
| 스킬 파일 | `%APPDATA%\AxCommander\skills\*.skill.json` |
|
||||||
|
| 크래시 덤프 | `%APPDATA%\AxCommander\crashes\` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 사용법
|
||||||
|
|
||||||
|
### 키보드 단축키
|
||||||
|
|
||||||
|
| 동작 | 단축키 |
|
||||||
|
|------|--------|
|
||||||
|
| 런처 열기 / 닫기 | `Alt+Space` |
|
||||||
|
| 설정 열기 | `Ctrl+,` |
|
||||||
|
| 다음 항목 선택 | `↓` |
|
||||||
|
| 이전 항목 선택 | `↑` |
|
||||||
|
| 실행 | `Enter` |
|
||||||
|
| 자동완성 (선택 항목 제목 채우기) | `Tab` |
|
||||||
|
| 닫기 | `Esc` |
|
||||||
|
|
||||||
|
### 계산기 예시
|
||||||
|
|
||||||
|
```
|
||||||
|
= 1 + 2 * 3 → 7
|
||||||
|
= sqrt(144) → 12
|
||||||
|
= 2^10 → 1024
|
||||||
|
= sin(30) → 0.5 (도 단위)
|
||||||
|
= log(1000) → 3
|
||||||
|
= pi * 5^2 → 78.5398...
|
||||||
|
= 0xFF + 16 → 271
|
||||||
|
= round(3.14159, 2) → 3.14
|
||||||
|
```
|
||||||
|
|
||||||
|
### 스니펫 변수
|
||||||
|
|
||||||
|
스니펫 내용에서 아래 변수를 사용할 수 있습니다:
|
||||||
|
|
||||||
|
| 변수 | 치환 값 | 예시 |
|
||||||
|
|------|---------|------|
|
||||||
|
| `{date}` | 오늘 날짜 | `2026-03-23` |
|
||||||
|
| `{time}` | 현재 시각 | `14:30:00` |
|
||||||
|
| `{datetime}` | 날짜+시각 | `2026-03-23 14:30:00` |
|
||||||
|
| `{year}` | 연도 | `2026` |
|
||||||
|
| `{month}` | 월 (2자리) | `03` |
|
||||||
|
| `{day}` | 일 (2자리) | `23` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 플러그인 개발
|
||||||
|
|
||||||
|
### DLL 플러그인
|
||||||
|
|
||||||
|
`AxCommander.SDK`를 참조하여 `IActionHandler` 인터페이스를 구현합니다.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using AxCommander.SDK;
|
||||||
|
|
||||||
|
public class MyHandler : IActionHandler
|
||||||
|
{
|
||||||
|
public string? Prefix => "?"; // 트리거 프리픽스 (null이면 prefix 없는 핸들러)
|
||||||
|
public PluginMetadata Metadata => new("MyPlugin", "설명", Version: "1.0");
|
||||||
|
|
||||||
|
public async Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
||||||
|
{
|
||||||
|
return [ new LauncherItem("제목", "부제목", null, myData, Symbol: "\uE721") ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
||||||
|
{
|
||||||
|
// item.Data로 전달한 데이터를 꺼내 실행 로직 작성
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
빌드한 DLL 경로를 `settings.json`의 `plugins` 배열에 추가:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
{ "path": "C:\\MyPlugins\\MyPlugin.dll", "enabled": true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### JSON 스킬 (코드 없이 HTTP API 연동)
|
||||||
|
|
||||||
|
`%APPDATA%\AxCommander\skills\` 에 `.skill.json` 파일을 놓으면 됩니다.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "github-search",
|
||||||
|
"name": "GitHub 검색",
|
||||||
|
"prefix": "@gh",
|
||||||
|
"credential": { "type": "bearer_token", "credentialKey": "github_token" },
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"url": "https://api.github.com/search/repositories?q={{INPUT}}&per_page=10"
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"resultsPath": "items",
|
||||||
|
"titleField": "full_name",
|
||||||
|
"subtitleField": "description",
|
||||||
|
"actionUrl": "html_url"
|
||||||
|
},
|
||||||
|
"cache": 30
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 테마
|
||||||
|
|
||||||
|
7가지 내장 테마와 완전 커스텀 테마를 지원합니다.
|
||||||
|
|
||||||
|
| 테마 | 특징 |
|
||||||
|
|------|------|
|
||||||
|
| `system` | Windows 다크/라이트 모드 자동 감지 |
|
||||||
|
| `dark` | 딥 네이비 다크 (기본) |
|
||||||
|
| `light` | 클린 화이트 라이트 |
|
||||||
|
| `oled` | 순수 블랙 (OLED 절전) |
|
||||||
|
| `nord` | Arctic 컬러 팔레트 |
|
||||||
|
| `monokai` | Sublime Text 스타일 |
|
||||||
|
| `catppuccin` | Mocha 따뜻한 파스텔 |
|
||||||
|
| `sepia` | 황갈색 아날로그 감성 |
|
||||||
|
| `custom` | 14개 색상 완전 커스터마이징 |
|
||||||
|
|
||||||
|
설정 UI(`Ctrl+,` → 테마 탭)에서 클릭 한 번으로 즉시 미리보기 적용.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 변경 이력
|
||||||
|
|
||||||
|
### v1.6.1 — 전체 점검 수정
|
||||||
|
|
||||||
|
| 분류 | 내용 |
|
||||||
|
|------|------|
|
||||||
|
| 빌드 오류 수정 | `using System.IO` 누락, `Key.Enter`/`Key.Return` 중복 switch 케이스, `EnumDisplayMonitors` 람다 타입 혼합, `icon.ico` 다이아몬드 픽셀 보석 아이콘으로 교체, nullable 역참조 경고 |
|
||||||
|
| 런타임 버그 수정 | JSON 스킬 경로 파싱(`field[0` 형식 오류 방지), 클립보드 서비스 스레드 안전성, 디바운스 타이머 원자적 교체, 설정 백업 실패 로깅 |
|
||||||
|
| 보안 수정 | JSON 스킬 `ActionUrl` 실행 전 `http`/`https` 스킴 검증 추가 |
|
||||||
|
| 데드 코드 제거 | `SystemCommandHandler` no-op `timer`/`alarm` 항목 제거 |
|
||||||
|
|
||||||
|
자세한 내용은 [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md)의 "v1.6 3차 전체 점검 수정" 섹션을 참고하세요.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 라이선스
|
||||||
|
|
||||||
|
MIT License
|
||||||
90
build.bat
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@echo off
|
||||||
|
chcp 65001 >nul
|
||||||
|
echo.
|
||||||
|
echo ========================================
|
||||||
|
echo AX Copilot - Build Script
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
set APP=src\AxCopilot\AxCopilot.csproj
|
||||||
|
set ENCRYPTOR=src\AxKeyEncryptor\AxKeyEncryptor.csproj
|
||||||
|
set OFFLINE=src\AxCopilot.Installer\AxCopilot.Installer.csproj
|
||||||
|
set OUT=dist
|
||||||
|
|
||||||
|
:: Kill running app
|
||||||
|
tasklist /FI "IMAGENAME eq AxCopilot.exe" 2>nul | find /i "AxCopilot.exe" >nul
|
||||||
|
if %ERRORLEVEL%==0 (
|
||||||
|
echo [0] Stopping AxCopilot...
|
||||||
|
taskkill /IM AxCopilot.exe /F >nul 2>nul
|
||||||
|
timeout /t 2 /nobreak >nul
|
||||||
|
)
|
||||||
|
:: Kill legacy process
|
||||||
|
tasklist /FI "IMAGENAME eq AxCommander.exe" 2>nul | find /i "AxCommander.exe" >nul
|
||||||
|
if %ERRORLEVEL%==0 (
|
||||||
|
echo [0] Stopping legacy AxCommander...
|
||||||
|
taskkill /IM AxCommander.exe /F >nul 2>nul
|
||||||
|
timeout /t 2 /nobreak >nul
|
||||||
|
)
|
||||||
|
|
||||||
|
if exist "%OUT%" rd /s /q "%OUT%" 2>nul
|
||||||
|
mkdir "%OUT%"
|
||||||
|
mkdir "%OUT%\AxCopilot"
|
||||||
|
|
||||||
|
:: ========================================
|
||||||
|
:: 1. Main app (self-contained, folder)
|
||||||
|
:: ========================================
|
||||||
|
echo [1/4] Building main app (self-contained)...
|
||||||
|
dotnet publish "%APP%" -c Release -o "%OUT%\AxCopilot" --self-contained true --nologo -v quiet
|
||||||
|
if %ERRORLEVEL% NEQ 0 ( echo [FAILED] Main app build & pause & exit /b 1 )
|
||||||
|
echo OK - dist\AxCopilot\
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ========================================
|
||||||
|
:: 2. AxKeyEncryptor (developer tool)
|
||||||
|
:: ========================================
|
||||||
|
echo [2/4] Building AxKeyEncryptor (WinForms)...
|
||||||
|
mkdir "%OUT%\AxKeyEncryptor" 2>nul
|
||||||
|
dotnet publish "%ENCRYPTOR%" -c Release -o "%OUT%\AxKeyEncryptor" --self-contained false --nologo -v quiet
|
||||||
|
if %ERRORLEVEL% NEQ 0 ( echo [FAILED] AxKeyEncryptor build & pause & exit /b 1 )
|
||||||
|
del /q "%OUT%\AxKeyEncryptor\*.pdb" 2>nul
|
||||||
|
echo OK - dist\AxKeyEncryptor\
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ========================================
|
||||||
|
:: 3. Create payload ZIP for installer
|
||||||
|
:: ========================================
|
||||||
|
echo [3/4] Creating installer payload ZIP...
|
||||||
|
powershell -NoProfile -Command "Compress-Archive -Path '%OUT%\AxCopilot\*' -DestinationPath 'src\AxCopilot.Installer\payload.zip' -Force"
|
||||||
|
echo OK - payload.zip
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ========================================
|
||||||
|
:: 4. Build installer (.NET Framework 4.8)
|
||||||
|
:: ========================================
|
||||||
|
echo [4/4] Building installer (.NET Framework 4.8)...
|
||||||
|
dotnet build "%OFFLINE%" -c Release --nologo -v quiet
|
||||||
|
if %ERRORLEVEL% NEQ 0 ( echo [FAILED] Installer build & pause & exit /b 1 )
|
||||||
|
copy /Y "src\AxCopilot.Installer\bin\Release\net48\AxCopilot_Setup.exe" "%OUT%\" >nul
|
||||||
|
for %%F in ("%OUT%\AxCopilot_Setup.exe") do echo OK - AxCopilot_Setup.exe (%%~zF bytes)
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ========================================
|
||||||
|
:: Cleanup
|
||||||
|
:: ========================================
|
||||||
|
:: Remove debug symbols and metadata (anti-decompile)
|
||||||
|
del /q "%OUT%\*.pdb" 2>nul
|
||||||
|
del /q "%OUT%\AxCopilot\*.pdb" 2>nul
|
||||||
|
del /q "%OUT%\AxCopilot\*.xml" 2>nul
|
||||||
|
del /q "%OUT%\*.deps.json" 2>nul
|
||||||
|
del /q "%OUT%\*.runtimeconfig.json" 2>nul
|
||||||
|
del /q "src\AxCopilot.Installer\payload.zip" 2>nul
|
||||||
|
|
||||||
|
echo ========================================
|
||||||
|
echo Build Complete!
|
||||||
|
echo ========================================
|
||||||
|
echo.
|
||||||
|
echo dist\AxCopilot\ Main app (EXE + DLL)
|
||||||
|
echo dist\AxKeyEncryptor\ Settings Encryptor (dev tool)
|
||||||
|
echo dist\AxCopilot_Setup.exe Installer (offline, .NET 4.8)
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
14
build_output.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
복원할 프로젝트를 확인하는 중...
|
||||||
|
E:\AX Copilot\src\AxCopilot\AxCopilot.csproj을(를) 1.41초 동안 복원했습니다.
|
||||||
|
E:\AX Copilot\src\AxCopilot.Tests\AxCopilot.Tests.csproj을(를) 1.41초 동안 복원했습니다.
|
||||||
|
복원할 4 프로젝트의 2이(가) 최신 상태입니다.
|
||||||
|
AxCopilot.SDK -> E:\AX Copilot\src\AxCopilot.SDK\bin\Debug\net8.0-windows\AxCopilot.SDK.dll
|
||||||
|
AxCopilot -> E:\AX Copilot\src\AxCopilot\bin\Debug\net8.0-windows\win-x64\AxCopilot.dll
|
||||||
|
AxKeyEncryptor -> E:\AX Copilot\src\AxKeyEncryptor\bin\Debug\net8.0-windows\AxKeyEncryptor.dll
|
||||||
|
AxCopilot.Tests -> E:\AX Copilot\src\AxCopilot.Tests\bin\Debug\net8.0-windows\AxCopilot.Tests.dll
|
||||||
|
|
||||||
|
빌드했습니다.
|
||||||
|
경고 0개
|
||||||
|
오류 0개
|
||||||
|
|
||||||
|
경과 시간: 00:00:07.34
|
||||||
BIN
dist/AxCopilot/Accessibility.dll
vendored
Normal file
BIN
dist/AxCopilot/Assets/SearchEngines/duckduckgo.png
vendored
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
dist/AxCopilot/Assets/SearchEngines/github.png
vendored
Normal file
|
After Width: | Height: | Size: 519 B |
BIN
dist/AxCopilot/Assets/SearchEngines/google.png
vendored
Normal file
|
After Width: | Height: | Size: 615 B |
BIN
dist/AxCopilot/Assets/SearchEngines/namuwiki.png
vendored
Normal file
|
After Width: | Height: | Size: 553 B |
BIN
dist/AxCopilot/Assets/SearchEngines/naver.png
vendored
Normal file
|
After Width: | Height: | Size: 247 B |
BIN
dist/AxCopilot/Assets/SearchEngines/navermap.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
dist/AxCopilot/Assets/SearchEngines/wikipedia.png
vendored
Normal file
|
After Width: | Height: | Size: 555 B |
BIN
dist/AxCopilot/Assets/SearchEngines/youtube.png
vendored
Normal file
|
After Width: | Height: | Size: 488 B |
BIN
dist/AxCopilot/Assets/guide_dev.enc
vendored
Normal file
BIN
dist/AxCopilot/Assets/guide_user.enc
vendored
Normal file
BIN
dist/AxCopilot/Assets/icon.ico
vendored
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
dist/AxCopilot/AxCopilot.SDK.dll
vendored
Normal file
1319
dist/AxCopilot/AxCopilot.deps.json
vendored
Normal file
BIN
dist/AxCopilot/AxCopilot.dll
vendored
Normal file
BIN
dist/AxCopilot/AxCopilot.exe
vendored
Normal file
19
dist/AxCopilot/AxCopilot.runtimeconfig.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"runtimeOptions": {
|
||||||
|
"tfm": "net8.0",
|
||||||
|
"includedFrameworks": [
|
||||||
|
{
|
||||||
|
"name": "Microsoft.NETCore.App",
|
||||||
|
"version": "8.0.25"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Microsoft.WindowsDesktop.App",
|
||||||
|
"version": "8.0.25"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configProperties": {
|
||||||
|
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
|
||||||
|
"CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||