Home
About
Blog
Products
Forum
Support
Contact
Sunbelt Computer Software
PL/B Language Development and Support
Home
About
Blog
Products
Forum
Support
Contact
skill-jam/scripts/build.py at main · dotnetdev-kr/skill-jam · GitHub
Skip to content
Navigation Menu
Sign in
Appearance settings
Platform
AI CODE CREATION
GitHub Copilot
Write better code with AI
GitHub Copilot app
Direct agents from issue to merge
MCP Registry
Integrate external tools
DEVELOPER WORKFLOWS
Actions
Automate any workflow
Codespaces
Instant dev environments
Issues
Plan and track work
Code Review
Manage code changes
Code Quality
Enforce quality at merge
APPLICATION SECURITY
GitHub Advanced Security
Find and fix vulnerabilities
Code security
Secure your code as you build
Secret protection
Stop leaks before they start
EXPLORE
Why GitHub
Documentation
Blog
Changelog
Marketplace
View all features
Solutions
BY COMPANY SIZE
Enterprises
Small and medium teams
Startups
Nonprofits
BY USE CASE
App Modernization
DevSecOps
DevOps
CI/CD
View all use cases
BY INDUSTRY
Healthcare
Financial services
Manufacturing
Government
See all industries
View all solutions
Resources
EXPLORE BY TOPIC
AI
Software Development
DevOps
Security
View all topics
EXPLORE BY TYPE
Customer stories
Events & webinars
Ebooks & reports
Business insights
GitHub Skills
SUPPORT & SERVICES
Documentation
Customer support
Community forum
Trust center
Partners
View all resources
Open Source
COMMUNITY
GitHub Sponsors
Fund open source developers
PROGRAMS
Security Lab
Maintainer Community
GitHub Stars
Archive Program
REPOSITORIES
Topics
Trending
Collections
Enterprise
ENTERPRISE SOLUTIONS
Enterprise platform
AI-powered developer platform
AVAILABLE ADD-ONS
GitHub Advanced Security
Enterprise-grade security features
Copilot for Business
Enterprise-grade AI features
Premium Support
Enterprise-grade 24/7 support
Pricing
Search
/
Sign in
Sign up
Appearance settings
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
dotnetdev-kr
skill-jam
Repository navigation
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
More
items
Files
Expand file tree
main
Breadcrumbs
skill-jam
/
scripts
/
build.py
Copy path
Blame
More file actions
Blame
More file actions
Latest commit
History
History
History
135 lines (126 loc) · 9.01 KB
main
Breadcrumbs
skill-jam
/
scripts
/
build.py
Copy path
Top
File metadata and controls
Code
Blame
135 lines (126 loc) · 9.01 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python3
"""Build portable HTML with Python's standard library, without network access."""
import
argparse
import
hashlib
from
html
import
escape
from
pathlib
import
Path
import
shutil
from
urllib
.
parse
import
urlparse
ROOT
=
Path
(
__file__
).
resolve
().
parents
[
1
]
DEFAULT_URL
=
"https://dotnetdev.kr/skill-jam/"
DESCRIPTION
=
"닷넷데브가 여는 한국 로컬 에이전트 기술 밋업. Skill, MCP Server, CLI, Tool, Agent와 Workflow의 구현 경험을 나눕니다. 첫 행사를 준비하고 있습니다."
TOPICS
=
[
{
"slug"
:
"skills"
,
"title"
:
"Agent Skills"
,
"type"
:
"INSTRUCTIONS & KNOW-HOW"
,
"description"
:
"반복하는 작업의 절차와 지식을 에이전트가 활용할 수 있도록 구성합니다. SKILL.md를 비롯한 지침을 직접 작성하고 실제 작업에 적용한 경험을 나눕니다."
,
"example"
:
"반복하던 코드 리뷰를 Skill로 구성하고, 지침이 모호해 실패했던 사례"
,
"tags"
: [
"SKILL.md"
,
"Context"
,
"Evaluation"
],
},
{
"slug"
:
"mcp"
,
"title"
:
"MCP Server"
,
"type"
:
"CONTEXT & CONNECTIONS"
,
"description"
:
"에이전트와 데이터, 도구를 연결한 구현을 다룹니다. 서버의 인터페이스와 인증, 오류 처리 등 연결 과정에서 어떤 설계를 선택했는지 공유합니다."
,
"example"
:
"사내 도구를 MCP Server로 연결하며 겪은 인증과 오류 처리 문제"
,
"tags"
: [
"MCP"
,
"Tools & Resources"
,
"Authentication"
],
},
{
"slug"
:
"cli"
,
"title"
:
"CLI"
,
"type"
:
"COMMANDS & COMPOSABILITY"
,
"description"
:
"에이전트가 호출할 명령줄 도구를 설계한 경험을 나눕니다. 입력과 출력 형식, 종료 코드, 재시도와 조합 방식을 실제 사용 흐름과 함께 설명합니다."
,
"example"
:
"사람이 쓰던 CLI를 에이전트도 다룰 수 있도록 바꾼 설계와 테스트"
,
"tags"
: [
"Structured output"
,
"Exit codes"
,
"Composability"
],
},
{
"slug"
:
"tools"
,
"title"
:
"Tool & Connector"
,
"type"
:
"ACTIONS & INTERFACES"
,
"description"
:
"Function Calling, API와 Connector로 에이전트의 실행 범위를 넓힌 과정을 다룹니다. 매개변수 설계와 권한 경계, 잘못된 호출을 처리한 방법도 공유합니다."
,
"example"
:
"기존 API를 에이전트 도구로 제공하며 매개변수와 실행 권한을 설계한 과정"
,
"tags"
: [
"Function Calling"
,
"API"
,
"Permissions"
],
},
{
"slug"
:
"agents"
,
"title"
:
"Agent & Workflow"
,
"type"
:
"ORCHESTRATION & HANDOFFS"
,
"description"
:
"여러 도구와 에이전트를 조합해 작업 흐름을 만든 경험을 나눕니다. Copilot Studio부터 직접 구성한 Agent까지, 사람의 검토를 어디에 두었는지도 함께 다룹니다."
,
"example"
:
"자료 조사와 초안 작성을 연결하고 사람의 검토 단계를 포함한 Workflow"
,
"tags"
: [
"Copilot Studio"
,
"Agent Framework"
,
"Human review"
],
},
{
"slug"
:
"infra"
,
"title"
:
"Agent Infrastructure"
,
"type"
:
"RUNTIME & RELIABILITY"
,
"description"
:
"에이전트가 실행되는 기반과 운영 경험을 다룹니다. Harness, Sandbox, Memory, 관측과 평가를 비롯해 실제 작업의 안정성을 높이려던 시도를 공유합니다."
,
"example"
:
"도구 실행을 Sandbox로 격리하고 실패한 작업의 로그를 추적한 과정"
,
"tags"
: [
"Harness"
,
"Sandbox"
,
"Observability"
],
},
]
def
explorer
(
selected
):
links
=
[]
for
number
,
topic
in
enumerate
(
TOPICS
,
1
):
slug
=
topic
[
"slug"
]
current
=
' aria-current="true"'
if
slug
==
selected
[
"slug"
]
else
""
links
.
append
(
f'<a id="topic-link-
{
slug
}
" class="topic-link" href="topic-
{
slug
}
.html#topic-explorer" '
f'hx-get="topic-
{
slug
}
.html" hx-target="#topic-explorer" hx-select="#topic-explorer" '
f'hx-swap="outerHTML ignoreTitle:true" hx-sync="closest #topic-explorer:replace"
{
current
}
>'
f'<span aria-hidden="true">
{
number
}
</span><span lang="en">
{
escape
(
topic
[
"title"
])
}
</span>'
'<span class="link-arrow" aria-hidden="true">↗</span></a>'
)
tags
=
""
.
join
(
f'<span lang="en">
{
escape
(
tag
)
}
</span>'
for
tag
in
selected
[
"tags"
])
return
(
'<div id="topic-explorer" class="topic-explorer">'
'<nav class="topic-nav" aria-label="기술별 발표 아이디어">'
+
""
.
join
(
links
)
+
'</nav>'
'<article class="topic-panel" aria-labelledby="topic-title">'
f'<div class="topic-type"><span lang="en">
{
escape
(
selected
[
"type"
])
}
</span><span lang="en">IDEA FILE</span></div>'
f'<div><h3 id="topic-title" lang="en">
{
escape
(
selected
[
"title"
])
}
</h3>'
f'<p class="topic-description">
{
escape
(
selected
[
"description"
])
}
</p></div>'
'<div class="topic-example"><p>이런 이야기로 시작할 수 있습니다.</p>'
f'<p>
{
escape
(
selected
[
"example"
])
}
</p><div class="topic-tags">
{
tags
}
</div></div></article></div>'
)
def
build
(
base_url
):
parsed
=
urlparse
(
base_url
)
if
parsed
.
scheme
not
in
(
"http"
,
"https"
)
or
not
parsed
.
netloc
or
parsed
.
query
or
parsed
.
fragment
:
raise
ValueError
(
"--base-url must be an absolute HTTP(S) site URL without query or fragment"
)
base_url
=
base_url
.
rstrip
(
"/"
)
+
"/"
output
=
ROOT
/
"dist"
if
output
.
exists
():
shutil
.
rmtree
(
output
)
shutil
.
copytree
(
ROOT
/
"site"
,
output
)
layout
=
(
ROOT
/
"templates/layout.html"
).
read_text
()
def
write_page
(
filename
,
body
,
title
,
description
):
canonical
=
base_url
+
(
""
if
filename
==
"index.html"
else
filename
)
html
=
layout
for
name
,
value
in
{
"TITLE"
:
escape
(
title
),
"DESCRIPTION"
:
escape
(
description
,
quote
=
True
),
"CANONICAL"
:
escape
(
canonical
,
quote
=
True
),
"BODY"
:
body
}.
items
():
html
=
html
.
replace
(
f"@@
{
name
}
@@"
,
value
)
if
"@@"
in
html
:
raise
ValueError
(
f"Unresolved template in
{
filename
}
"
)
# Refresh changed first-party assets without discarding long-lived vendor caches.
for
asset
in
(
"style.css"
,
"site.js"
,
"favicon.svg"
):
version
=
hashlib
.
sha256
((
output
/
"assets"
/
asset
).
read_bytes
()).
hexdigest
()[:
12
]
html
=
html
.
replace
(
f'"assets/
{
asset
}
"'
,
f'"assets/
{
asset
}
?v=
{
version
}
"'
)
(
output
/
filename
).
write_text
(
html
,
encoding
=
"utf-8"
)
home
=
(
ROOT
/
"templates/home.html"
).
read_text
().
replace
(
"@@EXPLORER@@"
,
explorer
(
TOPICS
[
0
]))
write_page
(
"index.html"
,
home
,
"Skill Jam | 닷넷데브 에이전트 기술 밋업 | Coming Soon"
,
DESCRIPTION
)
for
topic
in
TOPICS
:
body
=
(
'<section class="topic-page wrap"><a class="back-link" href="./#topics">← Skill Jam 발표 주제로 돌아가기</a>'
'<p class="eyebrow" lang="en">WHAT
\'
S YOUR BUILD?</p>'
f'<h1>
{
escape
(
topic
[
"title"
])
}
발표 아이디어</h1>'
'<p class="topic-page-intro">아래 내용은 발표 주제의 예시입니다. 첫 행사의 발표 프로그램은 아직 확정하지 않았습니다.</p>'
+
explorer
(
topic
)
+
'<p id="topic-status" class="topic-status" role="status" aria-live="polite" aria-atomic="true"></p>'
'<p id="topic-error" class="topic-error" role="alert" hidden>주제 내용을 불러오지 못했습니다. '
'<a href="./#topics">발표 주제로 돌아가기</a></p></section>'
)
write_page
(
f'topic-
{
topic
[
"slug"
]
}
.html'
,
body
,
f'
{
topic
[
"title"
]
}
발표 아이디어 | Skill Jam'
,
topic
[
"description"
])
write_page
(
"404.html"
,
'<section class="topic-page wrap"><p class="eyebrow">404</p><h1>페이지를 찾을 수 없습니다.</h1>'
f'<p class="topic-page-intro">주소가 바뀌었거나 존재하지 않는 페이지입니다.</p><a class="button button-dark" href="
{
escape
(
base_url
)
}
">Skill Jam 홈으로</a></section>'
,
"페이지를 찾을 수 없습니다 | Skill Jam"
,
"Skill Jam 홈에서 행사 소식과 발표 주제를 살펴볼 수 있습니다."
)
# A deep missing URL must still load the 404 page assets and navigation.
error_html
=
(
output
/
"404.html"
).
read_text
()
error_html
=
error_html
.
replace
(
'<head>'
,
f'<head>
\n
<base href="
{
escape
(
base_url
,
quote
=
True
)
}
">'
,
1
)
error_html
=
error_html
.
replace
(
'<meta name="description"'
,
'<meta name="robots" content="noindex">
\n
<meta name="description"'
,
1
)
(
output
/
"404.html"
).
write_text
(
error_html
)
urls
=
[
base_url
]
+
[
f'
{
base_url
}
topic-
{
t
[
"slug"
]
}
.html'
for
t
in
TOPICS
]
sitemap
=
'<?xml version="1.0" encoding="UTF-8"?>
\n
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
\n
'
sitemap
+=
"
\n
"
.
join
(
f' <url><loc>
{
escape
(
url
)
}
</loc></url>'
for
url
in
urls
)
+
'
\n
</urlset>
\n
'
(
output
/
"sitemap.xml"
).
write_text
(
sitemap
)
(
output
/
".nojekyll"
).
touch
()
print
(
f"Built
{
len
(
urls
)
+
1
}
HTML pages in
{
output
}
"
)
print
(
f"Canonical site URL:
{
base_url
}
"
)
if
__name__
==
"__main__"
:
parser
=
argparse
.
ArgumentParser
(
description
=
__doc__
)
parser
.
add_argument
(
"--base-url"
,
default
=
DEFAULT_URL
)
build
(
parser
.
parse_args
().
base_url
)
You can’t perform that action at this time.