wogiflow 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.workflow/agents/reviewer.md +81 -0
- package/.workflow/agents/security.md +94 -0
- package/.workflow/agents/story-writer.md +58 -0
- package/.workflow/bridges/base-bridge.js +395 -0
- package/.workflow/bridges/claude-bridge.js +434 -0
- package/.workflow/bridges/index.js +130 -0
- package/.workflow/lib/assumption-detector.js +481 -0
- package/.workflow/lib/config-substitution.js +371 -0
- package/.workflow/lib/failure-categories.js +478 -0
- package/.workflow/state/app-map.md.template +15 -0
- package/.workflow/state/architecture.md.template +24 -0
- package/.workflow/state/component-index.json.template +5 -0
- package/.workflow/state/decisions.md.template +15 -0
- package/.workflow/state/feedback-patterns.md.template +9 -0
- package/.workflow/state/knowledge-sync.json.template +6 -0
- package/.workflow/state/progress.md.template +14 -0
- package/.workflow/state/ready.json.template +7 -0
- package/.workflow/state/request-log.md.template +14 -0
- package/.workflow/state/session-state.json.template +11 -0
- package/.workflow/state/stack.md.template +33 -0
- package/.workflow/state/testing.md.template +36 -0
- package/.workflow/templates/claude-md.hbs +257 -0
- package/.workflow/templates/correction-report.md +67 -0
- package/.workflow/templates/gemini-md.hbs +52 -0
- package/README.md +1802 -0
- package/bin/flow +205 -0
- package/lib/index.js +33 -0
- package/lib/installer.js +467 -0
- package/lib/release-channel.js +269 -0
- package/lib/skill-registry.js +526 -0
- package/lib/upgrader.js +401 -0
- package/lib/utils.js +305 -0
- package/package.json +64 -0
- package/scripts/flow +985 -0
- package/scripts/flow-adaptive-learning.js +1259 -0
- package/scripts/flow-aggregate.js +488 -0
- package/scripts/flow-archive +133 -0
- package/scripts/flow-auto-context.js +1015 -0
- package/scripts/flow-auto-learn.js +615 -0
- package/scripts/flow-bridge.js +223 -0
- package/scripts/flow-browser-suggest.js +316 -0
- package/scripts/flow-bug.js +247 -0
- package/scripts/flow-cascade.js +711 -0
- package/scripts/flow-changelog +85 -0
- package/scripts/flow-checkpoint.js +483 -0
- package/scripts/flow-cli.js +403 -0
- package/scripts/flow-code-intelligence.js +760 -0
- package/scripts/flow-complexity.js +502 -0
- package/scripts/flow-config-set.js +152 -0
- package/scripts/flow-constants.js +157 -0
- package/scripts/flow-context +152 -0
- package/scripts/flow-context-init.js +482 -0
- package/scripts/flow-context-monitor.js +384 -0
- package/scripts/flow-context-scoring.js +886 -0
- package/scripts/flow-correct.js +458 -0
- package/scripts/flow-damage-control.js +985 -0
- package/scripts/flow-deps +101 -0
- package/scripts/flow-diff.js +700 -0
- package/scripts/flow-done +151 -0
- package/scripts/flow-done.js +489 -0
- package/scripts/flow-durable-session.js +1541 -0
- package/scripts/flow-entropy-monitor.js +345 -0
- package/scripts/flow-export-profile +349 -0
- package/scripts/flow-export-scanner.js +1046 -0
- package/scripts/flow-figma-confirm.js +400 -0
- package/scripts/flow-figma-extract.js +496 -0
- package/scripts/flow-figma-generate.js +683 -0
- package/scripts/flow-figma-index.js +909 -0
- package/scripts/flow-figma-match.js +617 -0
- package/scripts/flow-figma-mcp-server.js +518 -0
- package/scripts/flow-figma-pipeline.js +414 -0
- package/scripts/flow-file-ops.js +301 -0
- package/scripts/flow-gate-confidence.js +825 -0
- package/scripts/flow-guided-edit.js +659 -0
- package/scripts/flow-health +185 -0
- package/scripts/flow-health.js +413 -0
- package/scripts/flow-hooks.js +556 -0
- package/scripts/flow-http-client.js +249 -0
- package/scripts/flow-hybrid-detect.js +167 -0
- package/scripts/flow-hybrid-interactive.js +591 -0
- package/scripts/flow-hybrid-test.js +152 -0
- package/scripts/flow-import-profile +439 -0
- package/scripts/flow-init +253 -0
- package/scripts/flow-instruction-richness.js +827 -0
- package/scripts/flow-jira-integration.js +579 -0
- package/scripts/flow-knowledge-router.js +522 -0
- package/scripts/flow-knowledge-sync.js +589 -0
- package/scripts/flow-linear-integration.js +631 -0
- package/scripts/flow-links.js +774 -0
- package/scripts/flow-log-manager.js +559 -0
- package/scripts/flow-loop-enforcer.js +1246 -0
- package/scripts/flow-loop-retry-learning.js +630 -0
- package/scripts/flow-lsp.js +923 -0
- package/scripts/flow-map-index +348 -0
- package/scripts/flow-map-sync +201 -0
- package/scripts/flow-memory-blocks.js +668 -0
- package/scripts/flow-memory-compactor.js +350 -0
- package/scripts/flow-memory-db.js +1110 -0
- package/scripts/flow-memory-sync.js +484 -0
- package/scripts/flow-metrics.js +353 -0
- package/scripts/flow-migrate-ids.js +370 -0
- package/scripts/flow-model-adapter.js +802 -0
- package/scripts/flow-model-router.js +884 -0
- package/scripts/flow-models.js +1231 -0
- package/scripts/flow-morning.js +517 -0
- package/scripts/flow-multi-approach.js +660 -0
- package/scripts/flow-new-feature +86 -0
- package/scripts/flow-onboard +1042 -0
- package/scripts/flow-orchestrate-llm.js +459 -0
- package/scripts/flow-orchestrate.js +3592 -0
- package/scripts/flow-output.js +123 -0
- package/scripts/flow-parallel-detector.js +399 -0
- package/scripts/flow-parallel-dispatch.js +987 -0
- package/scripts/flow-parallel.js +428 -0
- package/scripts/flow-pattern-enforcer.js +600 -0
- package/scripts/flow-prd-manager.js +282 -0
- package/scripts/flow-progress.js +323 -0
- package/scripts/flow-project-analyzer.js +975 -0
- package/scripts/flow-prompt-composer.js +487 -0
- package/scripts/flow-providers.js +1381 -0
- package/scripts/flow-queue.js +308 -0
- package/scripts/flow-ready +82 -0
- package/scripts/flow-ready.js +189 -0
- package/scripts/flow-regression.js +396 -0
- package/scripts/flow-response-parser.js +450 -0
- package/scripts/flow-resume.js +284 -0
- package/scripts/flow-rules-sync.js +439 -0
- package/scripts/flow-run-trace.js +718 -0
- package/scripts/flow-safety.js +587 -0
- package/scripts/flow-search +104 -0
- package/scripts/flow-security.js +481 -0
- package/scripts/flow-session-end +106 -0
- package/scripts/flow-session-end.js +437 -0
- package/scripts/flow-session-state.js +671 -0
- package/scripts/flow-setup-hooks +216 -0
- package/scripts/flow-setup-hooks.js +377 -0
- package/scripts/flow-skill-create.js +329 -0
- package/scripts/flow-skill-creator.js +572 -0
- package/scripts/flow-skill-generator.js +1046 -0
- package/scripts/flow-skill-learn.js +880 -0
- package/scripts/flow-skill-matcher.js +578 -0
- package/scripts/flow-spec-generator.js +820 -0
- package/scripts/flow-stack-wizard.js +895 -0
- package/scripts/flow-standup +162 -0
- package/scripts/flow-start +74 -0
- package/scripts/flow-start.js +235 -0
- package/scripts/flow-status +110 -0
- package/scripts/flow-status.js +301 -0
- package/scripts/flow-step-browser.js +83 -0
- package/scripts/flow-step-changelog.js +217 -0
- package/scripts/flow-step-comments.js +306 -0
- package/scripts/flow-step-complexity.js +234 -0
- package/scripts/flow-step-coverage.js +218 -0
- package/scripts/flow-step-knowledge.js +193 -0
- package/scripts/flow-step-pr-tests.js +364 -0
- package/scripts/flow-step-regression.js +89 -0
- package/scripts/flow-step-review.js +516 -0
- package/scripts/flow-step-security.js +162 -0
- package/scripts/flow-step-silent-failures.js +290 -0
- package/scripts/flow-step-simplifier.js +346 -0
- package/scripts/flow-story +105 -0
- package/scripts/flow-story.js +500 -0
- package/scripts/flow-suspend.js +252 -0
- package/scripts/flow-sync-daemon.js +654 -0
- package/scripts/flow-task-analyzer.js +606 -0
- package/scripts/flow-team-dashboard.js +748 -0
- package/scripts/flow-team-sync.js +752 -0
- package/scripts/flow-team.js +977 -0
- package/scripts/flow-tech-options.js +528 -0
- package/scripts/flow-templates.js +812 -0
- package/scripts/flow-tiered-learning.js +728 -0
- package/scripts/flow-trace +204 -0
- package/scripts/flow-transcript-chunking.js +1106 -0
- package/scripts/flow-transcript-digest.js +7918 -0
- package/scripts/flow-transcript-language.js +465 -0
- package/scripts/flow-transcript-parsing.js +1085 -0
- package/scripts/flow-transcript-stories.js +2194 -0
- package/scripts/flow-update-map +224 -0
- package/scripts/flow-utils.js +2242 -0
- package/scripts/flow-verification.js +644 -0
- package/scripts/flow-verify.js +1177 -0
- package/scripts/flow-voice-input.js +638 -0
- package/scripts/flow-watch +168 -0
- package/scripts/flow-workflow-steps.js +521 -0
- package/scripts/flow-workflow.js +1029 -0
- package/scripts/flow-worktree.js +489 -0
- package/scripts/hooks/adapters/base-adapter.js +102 -0
- package/scripts/hooks/adapters/claude-code.js +359 -0
- package/scripts/hooks/adapters/index.js +79 -0
- package/scripts/hooks/core/component-check.js +341 -0
- package/scripts/hooks/core/index.js +35 -0
- package/scripts/hooks/core/loop-check.js +241 -0
- package/scripts/hooks/core/session-context.js +294 -0
- package/scripts/hooks/core/task-gate.js +177 -0
- package/scripts/hooks/core/validation.js +230 -0
- package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
- package/scripts/hooks/entry/claude-code/session-end.js +87 -0
- package/scripts/hooks/entry/claude-code/session-start.js +46 -0
- package/scripts/hooks/entry/claude-code/stop.js +43 -0
- package/scripts/postinstall.js +139 -0
- package/templates/browser-test-flow.json +56 -0
- package/templates/bug-report.md +43 -0
- package/templates/component-detail.md +42 -0
- package/templates/component.stories.tsx +49 -0
- package/templates/context/constraints.md +83 -0
- package/templates/context/conventions.md +177 -0
- package/templates/context/stack.md +60 -0
- package/templates/correction-report.md +90 -0
- package/templates/feature-proposal.md +35 -0
- package/templates/hybrid/_base.md +254 -0
- package/templates/hybrid/_patterns.md +45 -0
- package/templates/hybrid/create-component.md +127 -0
- package/templates/hybrid/create-file.md +56 -0
- package/templates/hybrid/create-hook.md +145 -0
- package/templates/hybrid/create-service.md +70 -0
- package/templates/hybrid/fix-bug.md +33 -0
- package/templates/hybrid/modify-file.md +55 -0
- package/templates/story.md +68 -0
- package/templates/task.json +56 -0
- package/templates/trace.md +69 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Suspend Command
|
|
5
|
+
*
|
|
6
|
+
* Suspend the current task with a resume condition.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* flow suspend --wait-ci "gh run view 1234" # Wait for CI/CD
|
|
10
|
+
* flow suspend --rate-limit 60 # Wait N seconds
|
|
11
|
+
* flow suspend --review "Check PR #456" # Wait for human review
|
|
12
|
+
* flow suspend --wait-file "deploy-ready.json" # Wait for file
|
|
13
|
+
* flow suspend --schedule "2024-01-06T09:00:00" # Wait until time
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
loadDurableSession,
|
|
18
|
+
suspendSession,
|
|
19
|
+
isSuspended,
|
|
20
|
+
getSuspensionStatus,
|
|
21
|
+
SUSPENSION_TYPE,
|
|
22
|
+
RESUME_CONDITION
|
|
23
|
+
} = require('./flow-durable-session');
|
|
24
|
+
const { color, getConfig } = require('./flow-utils');
|
|
25
|
+
const { validateCommand } = require('./flow-workflow');
|
|
26
|
+
|
|
27
|
+
function parseArgs() {
|
|
28
|
+
const args = process.argv.slice(2);
|
|
29
|
+
const options = {
|
|
30
|
+
type: null,
|
|
31
|
+
reason: null,
|
|
32
|
+
resumeCondition: null
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < args.length; i++) {
|
|
36
|
+
const arg = args[i];
|
|
37
|
+
const nextArg = args[i + 1];
|
|
38
|
+
|
|
39
|
+
switch (arg) {
|
|
40
|
+
case '--wait-ci':
|
|
41
|
+
case '-c':
|
|
42
|
+
// SECURITY: Validate command before storing
|
|
43
|
+
if (nextArg) {
|
|
44
|
+
const validation = validateCommand(nextArg);
|
|
45
|
+
if (validation.blocked) {
|
|
46
|
+
console.error(color('red', `Error: Unsafe command rejected - ${validation.reason}`));
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
options.type = SUSPENSION_TYPE.CI_CD;
|
|
51
|
+
options.reason = `Waiting for CI/CD: ${nextArg}`;
|
|
52
|
+
options.resumeCondition = {
|
|
53
|
+
type: RESUME_CONDITION.POLL,
|
|
54
|
+
poll: {
|
|
55
|
+
command: nextArg,
|
|
56
|
+
expectedValue: 'completed',
|
|
57
|
+
intervalSeconds: 60,
|
|
58
|
+
maxAttempts: 120
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
i++;
|
|
62
|
+
break;
|
|
63
|
+
|
|
64
|
+
case '--rate-limit':
|
|
65
|
+
case '-r':
|
|
66
|
+
const seconds = parseInt(nextArg, 10);
|
|
67
|
+
options.type = SUSPENSION_TYPE.RATE_LIMIT;
|
|
68
|
+
options.reason = `Rate limited for ${seconds} seconds`;
|
|
69
|
+
const resumeTime = new Date(Date.now() + seconds * 1000).toISOString();
|
|
70
|
+
options.resumeCondition = {
|
|
71
|
+
type: RESUME_CONDITION.TIME,
|
|
72
|
+
time: { resumeAfter: resumeTime }
|
|
73
|
+
};
|
|
74
|
+
i++;
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
case '--review':
|
|
78
|
+
case '-R':
|
|
79
|
+
options.type = SUSPENSION_TYPE.HUMAN_REVIEW;
|
|
80
|
+
options.reason = `Awaiting human review: ${nextArg}`;
|
|
81
|
+
options.resumeCondition = {
|
|
82
|
+
type: RESUME_CONDITION.MANUAL,
|
|
83
|
+
manual: { prompt: nextArg }
|
|
84
|
+
};
|
|
85
|
+
i++;
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case '--wait-file':
|
|
89
|
+
case '-f':
|
|
90
|
+
options.type = SUSPENSION_TYPE.EXTERNAL_EVENT;
|
|
91
|
+
options.reason = `Waiting for file: ${nextArg}`;
|
|
92
|
+
options.resumeCondition = {
|
|
93
|
+
type: RESUME_CONDITION.FILE,
|
|
94
|
+
file: { watchPath: nextArg }
|
|
95
|
+
};
|
|
96
|
+
i++;
|
|
97
|
+
break;
|
|
98
|
+
|
|
99
|
+
case '--schedule':
|
|
100
|
+
case '-s':
|
|
101
|
+
options.type = SUSPENSION_TYPE.SCHEDULED;
|
|
102
|
+
options.reason = `Scheduled resume at: ${nextArg}`;
|
|
103
|
+
options.resumeCondition = {
|
|
104
|
+
type: RESUME_CONDITION.TIME,
|
|
105
|
+
time: { resumeAfter: new Date(nextArg).toISOString() }
|
|
106
|
+
};
|
|
107
|
+
i++;
|
|
108
|
+
break;
|
|
109
|
+
|
|
110
|
+
case '--long-running':
|
|
111
|
+
case '-l':
|
|
112
|
+
options.type = SUSPENSION_TYPE.LONG_RUNNING;
|
|
113
|
+
options.reason = `Long-running task: ${nextArg || 'Manual progress tracking'}`;
|
|
114
|
+
options.resumeCondition = {
|
|
115
|
+
type: RESUME_CONDITION.MANUAL,
|
|
116
|
+
manual: { prompt: nextArg || 'Continue when ready' }
|
|
117
|
+
};
|
|
118
|
+
if (nextArg && !nextArg.startsWith('-')) i++;
|
|
119
|
+
break;
|
|
120
|
+
|
|
121
|
+
case '--reason':
|
|
122
|
+
options.reason = nextArg;
|
|
123
|
+
i++;
|
|
124
|
+
break;
|
|
125
|
+
|
|
126
|
+
case '--help':
|
|
127
|
+
case '-h':
|
|
128
|
+
printHelp();
|
|
129
|
+
process.exit(0);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return options;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function printHelp() {
|
|
138
|
+
console.log(`
|
|
139
|
+
Wogi Flow - Suspend Command
|
|
140
|
+
|
|
141
|
+
Suspend the current task with a resume condition.
|
|
142
|
+
|
|
143
|
+
Usage:
|
|
144
|
+
flow suspend [options]
|
|
145
|
+
|
|
146
|
+
Options:
|
|
147
|
+
--wait-ci, -c <command> Wait for CI/CD (poll command until "completed")
|
|
148
|
+
--rate-limit, -r <seconds> Wait for N seconds (rate limiting)
|
|
149
|
+
--review, -R <message> Wait for human review/approval
|
|
150
|
+
--wait-file, -f <path> Wait for file to exist
|
|
151
|
+
--schedule, -s <datetime> Wait until specific time (ISO 8601)
|
|
152
|
+
--long-running, -l [msg] Long-running task with manual progress
|
|
153
|
+
--reason <text> Custom reason message
|
|
154
|
+
--help, -h Show this help
|
|
155
|
+
|
|
156
|
+
Examples:
|
|
157
|
+
flow suspend --wait-ci "gh run view 1234 --json status -q '.status'"
|
|
158
|
+
flow suspend --rate-limit 60
|
|
159
|
+
flow suspend --review "Check PR #456 before continuing"
|
|
160
|
+
flow suspend --wait-file ".workflow/state/deploy-ready.json"
|
|
161
|
+
flow suspend --schedule "2024-01-06T09:00:00"
|
|
162
|
+
flow suspend --long-running "Multi-day implementation"
|
|
163
|
+
`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function main() {
|
|
167
|
+
// Handle help first (before any other checks)
|
|
168
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
169
|
+
printHelp();
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const config = getConfig();
|
|
174
|
+
|
|
175
|
+
// Check if durable steps are enabled
|
|
176
|
+
if (config.durableSteps?.enabled === false) {
|
|
177
|
+
console.log(color('red', 'Durable steps are disabled. Enable in config.json to use suspend/resume.'));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Check for active session
|
|
182
|
+
const session = loadDurableSession();
|
|
183
|
+
if (!session) {
|
|
184
|
+
console.log(color('red', 'No active task session. Start a task first with /wogi-start.'));
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Check if already suspended
|
|
189
|
+
if (isSuspended()) {
|
|
190
|
+
const status = getSuspensionStatus();
|
|
191
|
+
console.log(color('yellow', 'Task is already suspended:'));
|
|
192
|
+
console.log(` Type: ${status.type}`);
|
|
193
|
+
console.log(` Reason: ${status.reason}`);
|
|
194
|
+
console.log(` Since: ${status.suspendedAt}`);
|
|
195
|
+
console.log('');
|
|
196
|
+
console.log(`Use ${color('cyan', 'flow resume')} to resume.`);
|
|
197
|
+
process.exit(0);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Parse arguments
|
|
201
|
+
const options = parseArgs();
|
|
202
|
+
|
|
203
|
+
if (!options.type) {
|
|
204
|
+
console.log(color('red', 'Please specify a suspend type. Use --help for options.'));
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Suspend the session
|
|
209
|
+
const result = suspendSession({
|
|
210
|
+
type: options.type,
|
|
211
|
+
reason: options.reason,
|
|
212
|
+
resumeCondition: options.resumeCondition
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (!result) {
|
|
216
|
+
console.log(color('red', 'Failed to suspend session.'));
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Display confirmation
|
|
221
|
+
console.log('');
|
|
222
|
+
console.log(color('yellow', '⏸️ Task Suspended'));
|
|
223
|
+
console.log(color('yellow', '─'.repeat(50)));
|
|
224
|
+
console.log(`Task: ${session.taskId}`);
|
|
225
|
+
console.log(`Type: ${options.type}`);
|
|
226
|
+
console.log(`Reason: ${options.reason}`);
|
|
227
|
+
console.log('');
|
|
228
|
+
|
|
229
|
+
// Show resume info
|
|
230
|
+
switch (options.resumeCondition.type) {
|
|
231
|
+
case RESUME_CONDITION.TIME:
|
|
232
|
+
console.log(`Resume at: ${options.resumeCondition.time.resumeAfter}`);
|
|
233
|
+
break;
|
|
234
|
+
case RESUME_CONDITION.POLL:
|
|
235
|
+
console.log(`Polling: ${options.resumeCondition.poll.command}`);
|
|
236
|
+
console.log(`Expected: ${options.resumeCondition.poll.expectedValue}`);
|
|
237
|
+
break;
|
|
238
|
+
case RESUME_CONDITION.MANUAL:
|
|
239
|
+
console.log(`Waiting for: ${options.resumeCondition.manual.prompt}`);
|
|
240
|
+
break;
|
|
241
|
+
case RESUME_CONDITION.FILE:
|
|
242
|
+
console.log(`Watching: ${options.resumeCondition.file.watchPath}`);
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log('');
|
|
247
|
+
console.log(`To resume: ${color('cyan', 'flow resume')}`);
|
|
248
|
+
console.log(`To force resume: ${color('cyan', 'flow resume --force')}`);
|
|
249
|
+
console.log(color('yellow', '─'.repeat(50)));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
main();
|